/**
 * Author: Snail(snail_email@163.com)
 *
 *
 * 样例：
 *
 * Snail(function($){
 *
 *    var type = $.request.getParament('type');
 *    type = ($.isBlank(type) ? 'H' : type.toLowerCase());
 *
 *    $.setEleAttribute('.board-main>iframe:nth-child(1)', {src: ('./index-1.html?type=' + type)});
 *    $.setEleAttribute('.board-main>iframe:nth-child(2)', {src: ('./index-2.html?' + type)});
 * });
 *
 * Snail.toDate('2018-08-10 13:55:03.89') ;
 * 
 * Snail.isBlank(obj);
 * 
 * Snail.toJSONString(obj);
 * 
 * Snail.extend(obj, newObj);
 * 
 * Snail.extend(obj, newObj, true);
 * 
 */
;var Snail = (function(_Snail, _win, _doc, undefined){
	
	
	function isFunction(obj){
		return Object.prototype.toString.call(obj) === '[object Function]';
	}
	
	function isArray( obj ) {
		return Object.prototype.toString.call(obj) === '[object Array]';
	}
	
	function isObject(obj){
		return Object.prototype.toString.call(obj) === '[object Object]';
	}
	
	function isNumber(obj){
		return Object.prototype.toString.call(obj) === '[object Number]';
	}
	
	function isString(obj){
		return Object.prototype.toString.call(obj) === '[object String]';
	}

	function isHTMLElement(obj){
		return /\[object\sHTML\w*Element\]/.test(Object.prototype.toString.call(obj));
	}

	function isBlank(obj){
		
		if(null == obj || undefined == obj){
			return true;
		}
		
		if(Snail.isString(obj)){
			
			if(/\S+/.test(obj)){
				return false;
			}
		}else if(Snail.isArray(obj)){
			
			if(0 < obj.length){
				return false;
			}
		}else if(Snail.isObject(obj)){
			
			for(var n in obj){
				return false;
			}
			
			return true;
		}else{
			return false;
		}
		
		return true;
	}

	_Snail = _Snail || function(fn){

		_win.onload = function(){

			if(isFunction(fn)){
				fn(_Snail, _win, _doc, undefined);
			}else if(isObject(fn)){

				for(var n in fn){
					if(undefined == _Snail[n]){
						_Snail[n] = fn[n];
					}
				}
			}
		}
	};

	_Snail.isBlank = isBlank;
	
	_Snail.isFunction = isFunction;
	
	_Snail.isArray = isArray;
	
	_Snail.isObject = isObject;
	
	_Snail.isNumber = isNumber;
	
	_Snail.isString = isString;
	
	_Snail.isHTMLElement = isHTMLElement;
	
	_Snail.extend = function() {
		
		if(arguments.length < 1){
			return ;
		}
		
		var _o = _Snail;
		var obj = null;
		var isReplace = false;
		
		if(1 == arguments.length){
			obj = arguments[0];
		} else if(2 == arguments.length || 3 == arguments.length){
			
			if(isString(arguments[0])) {
				
				if(_Snail[arguments[0]]){
					return;
				}
				
				_o = _Snail[arguments[0]] = {};
				
			} else if(isObject(arguments[0])){
				_o = arguments[0];
			} else {
				return ;
			}
			
			obj = arguments[1];
			
			if(3 == arguments.length){
				isReplace = ((true == arguments[2]) ? true : false);
			}
		} else {
			return ;
		}
		
		if(isFunction(obj)) {
			obj = obj(_Snail, _win, _doc);
		}
		
		if(!isObject(obj)){
			return ;
		}
		
		
		for(var name in obj){
			
			if(_o[name] && !isObject(_o[name]) && (false == isReplace)){
				continue;
			}
			
			if(isObject(obj[name])
				&& isObject(_o[name])){
				
				_Snail.extend(_o[name], obj[name]);
				
				continue;
			}
			
			_o[name] = obj[name];
		}
		
		return _o;
	}
		
	return _Snail;
})(Snail, window, document);



/* 扩展方法 */
Snail.extend({

	/**
	 * 将字符串转化为日期
	 * 样例：
	 * Snail.toDate('2018-08-10') 
	 * Snail.toDate('2018-08-10 13:55:03.89') 
	 */
	toDate: function(sDate, fmt){
		
		try {
			
			var times = Date.parse(sDate);
			
			if(isNaN(times)) {
				throw 'Invalid Date';
			}
			
			return new Date(times);

		} catch(error) {
			
			if(Snail.isBlank(sDate)){
				return null;
			}
			
			if(Snail.isBlank(fmt)){
				fmt = 'yyyy-MM-dd';
			}
			
			var part = {
					'y': function(date, fn){ // 年
						
						var num = fn('y', 4);
						
						if(-1 == num){
							return ;
						}
						
						date.setYear(num);
					},			
					'M' : function(date, fn){ // 月
						
						var num = fn('M', 2);
						
						if(-1 == num){
							return ;
						}

						date.setMonth(num - 1);
					},
					'd' : function(date, fn){ // 日 
						
						var num = fn('d', 2);

						if(-1 == num){
							return ;
						}

						date.setDate(num);
					},	  
					'H' : function(date, fn){ // 时
						
						var num = fn('H', 2);

						if(-1 == num){
							return ;
						}

						date.setHours(num);
					},				    
					'm' : function(date, fn){ // 分
						
						var num = fn('m', 2);

						if(-1 == num){
							return ;
						}

						date.setMinutes(num);
					},			   
					's' : function(date, fn){ // 秒
						
						var num = fn('s', 2);

						if(-1 == num){
							return ;
						}

						date.setSeconds(num);
					},			  
					'S' : function(date, fn){ // 毫秒
						
						var num = fn('S', 3);

						if(-1 == num){
							return ;
						}

						date.setMilliseconds(num);
					}		   
			};
			
			var fn = function(type, len){
				
				var i = fmt.indexOf(type);
				
				if(-1 == i){
					return -1;
				}
				
				var l = fmt.lastIndexOf(type);
				
				while((l - i + 1) < len){ // 优化日期格式化字符串
					fmt = fmt.substring(0, i) + type + fmt.substring(i);
					l++;
				}
				
				var str = sDate.substring(i);
				str = str.substring(0, (((l = str.search(/[^\d]/)) == -1) ? str.length : l));
				
				if(null == str || '' === str){
					throw 'Invalid Date';
				}
				
				while(str.length < len){ // 优化日期字符串
					sDate = sDate.substring(0, i) + '0' + sDate.substring(i);
					str = '0' + str;
				}
				
				if(/[^\d]/.test(str)){
					throw 'Invalid Date';
				}
				
				return new Number(str);
			};
			
			var date = new Date();
			
			for(var p in part){
				part[p](date, fn);
			}
			
			return date;				
		}
		
	},

	/**
	 * 日期格式化
	 * 样例：
	 * Snail.dateFormat(new Date(), 'yyyy-MM-dd')	-> 2018-08-10
	 * Snail.dateFormat(new Date(), 'yyyy/MM/dd')	-> 2018/08/10
	 * Snail.dateFormat(new Date(), 'yyyy年M月d日')	-> 2018年8月10日
	 * Snail.dateFormat(new Date(), 'yy年MM月dd日')	-> 08年08月10日
	 * Snail.dateFormat(new Date(), 'yyyy年第q季度')	-> 2018年第3季度
	 * Snail.dateFormat(new Date(), 'yyyy-MM-dd HH:mm:ss')		-> 2018-08-10 13:55:03
	 * Snail.dateFormat(new Date(), 'yyyy-MM-dd HH:mm:ss.S')	-> 2018-08-10 13:55:03.89
	 * Snail.dateFormat(new Date())	-> 2018-08-10
	 */
	dateFormat: function(date, fmt){
		
		if(Snail.isBlank(date)){
			return null;
		}
		
		if(Snail.isBlank(fmt)){
			fmt = 'yyyy-MM-dd';
		}
		
		var tem = 0;
		
		var part = {
				'y{4}': date.getFullYear(),			// 年份(4位)
				'y{2}': date.getFullYear() % 10,	// 年份(2位)
				'y': date.getFullYear(),			// 年份(4位)
				'q' : Math.floor((date.getMonth() + 3) / 3),	// 季度  
				'M{2}' : ((tem = (date.getMonth() + 1)) < 10 ? ('0' + tem) : tem),	// 月份
				'M' : date.getMonth() + 1,			// 月份   
				'd{2}' : ((tem = date.getDate()) < 10 ? ('0' + tem) : tem),			// 日
				'd' : date.getDate(),				// 日   
				'H{2}' : ((tem = date.getHours()) < 10 ? ('0' + tem) : tem),		// 小时  
				'H' : date.getHours(),				// 小时    
				'm{2}' : ((tem = date.getMinutes()) < 10 ? ('0' + tem) : tem),		// 分  
				'm' : date.getMinutes(),			// 分   
				's{2}' : ((tem = date.getSeconds()) < 10 ? ('0' + tem) : tem),		// 秒 
				's' : date.getSeconds(),			// 秒  
				'S' : date.getMilliseconds()		// 毫秒   
		};
		
		for(var p in part){
			fmt = fmt.replace(new RegExp(p), part[p]);
		}
		
		return fmt;
	},
	
	
	/**
	 * 修改日期
	 * 样例：
	 * Snail.plusDate(new Date(), 'S', 300)	-> 2018-08-10 13:55:03.8 -> 2018-08-10 13:55:03.308
	 * Snail.plusDate(new Date(), 's', 30)	-> 2018-08-10 13:55:03.8 -> 2018-08-10 13:55:33.8
	 * Snail.plusDate(new Date(), 'm', 3)	-> 2018-08-10 13:55:03.8 -> 2018-08-10 13:58:03.8
	 * Snail.plusDate(new Date(), 'H', 3)	-> 2018-08-10 13:55:03.8 -> 2018-08-10 16:55:03.8
	 * Snail.plusDate(new Date(), 'd', 3)	-> 2018-08-10 13:55:03.8 -> 2018-08-13 13:55:03.8
	 * Snail.plusDate(new Date(), 'M', 3)	-> 2018-08-10 13:55:03.8 -> 2018-11-10 13:55:03.8
	 * Snail.plusDate(new Date(), 'Y', 3)	-> 2018-08-10 13:55:03.8 -> 2021-08-10 13:55:03.8
	 */
	plusDate: function(date, fmt, num){
		
		if(null == date){
			date = new Date();
		} else{
			var times = date.getTime();
			date = new Date();
			date.setTime(times);
		}
		
		if(Snail.isBlank(fmt)){
			fmt = 'S';
		}
		
		if(null == num || 0 == num){
			return date;
		}
		
		var times = date.getTime();
		
		switch(fmt){
			case 's':{
				times += num * 1000;
				break;
			}
			case 'm':{
				times += num * 60 * 1000;
				break;
			}
			case 'H':{
				times += num * 60* 60 * 1000;
				break;
			}
			case 'd':{
				times += num * 24 * 60* 60 * 1000;
				break;
			}
			case 'M':{
				
				if(0 < num){
					num = date.getMonth() + num;
					
					if(11 >= num){
						date.setMonth(num);
					}else{
						y = Math.floor(num / 11);
						date.setFullYear(date.getFullYear() + y);
						date.setMonth(num % 11);
					}
					
				}else{
					
					num = date.getMonth() + num;
					
					if(0 <= num){
						date.setMonth(num);
					}else{
						num = Math.abs(num);
						y = Math.floor(num / 11);
						date.setFullYear(date.getFullYear() - (y + 1));
						date.setMonth((12 - (num % 11)));
					}
				}
				
				return date;
			}
			case 'y':{
				date.setFullYear(date.getFullYear() + num);
				return date;
			}
			default:
				times += num;
		}
		
		date.setTime(times);
		
		return date;
	},
	
	
	__CACHE__: (window.top['__SNAIL_CACHE_20210519__'] = window.top['__SNAIL_CACHE_20210519__'] || {}),
	
	/**
	 * 加入到缓存
	 */
	put: function(key, value){
		
		if(!key){
			return ;
		}
		
		Snail.__CACHE__[key] = value;
		
		// 深度缓存，缓存到Cookie
		if(arguments.length == 3 && true == arguments[2]){
			Snail.cookie.setCookie(key, value);
		}
	}, 
	
	/**
	 * 从缓存中提取数据
	 */
	get: function(key){
		
		if(!key){
			return null;
		}
		
		return Snail.__CACHE__[key] || Snail.cookie.getCookie(key);
	}, 


	__LISTENER__: (window.top['__SNAIL_LISTENER_20210519__'] = window.top['__SNAIL_LISTENER_20210519__'] || {}),


	/**
	 * 监听事件
	 * 
	 * 样例：
	 * Snail.$no('send', function(num, num2){
	 * 	alert(num);
	 * 	alert(num2);
	 * });
	 */
	$on: function(event, listener){

		if(!listener){
			return ;
		}

		if(Snail.__LISTENER__[event]){
			Snail.logger(event + '已注册，请勿重复注册！！！');
		}
		
		Snail.__LISTENER__[event] = listener;

	},

	/**
	 * 触发事件
	 * 
	 * 样例：
	 * Snail.$emit('send', 1, 2);
	 */
	$emit: function(event){

		if(Snail.__LISTENER__[event]){

			if(1 == arguments.length){

				Snail.__LISTENER__[event]();

			}else if( 1 < arguments.length){
				
				var args = [];

				for(var i=1, len=arguments.length; i<len; i++){

					args.push(arguments[i]);
				}

				Snail.__LISTENER__[event].apply({}, args);
			}
		}
	},
	
	logger: function(txt){
		
		try {
			console.log(txt);	
		} catch(e){}
	},
	
	/**
	 * 将JSON对象转JSON字符串
	 */
	toJSONString: function(obj){
		
		if(!obj){
			return null;
		}
		
		if(obj.toJSONString){
			
			return obj.toJSONString();
			
		} else if(JSON && JSON.stringify){
			
			return JSON.stringify(obj, function(key, value){
				
				if(typeof value === "undefined"){
					return null;
				}
				
				return value;
			});
		}

		
		/* Begin:简单实现JSON对象转JSON字符串  */
		var strJson = '';
		var depth = (2 == arguments.length && Snail.isNumber(arguments[1])) ? arguments[1] : 0;
		
		if(Snail.isObject(obj)){
			
			for(var name in obj){
				
				if(Snail.isObject(obj[name]) || Snail.isArray(obj[name])){
					
					if(depth < 100) {
						strJson += ', "' + name + '": ' + Snail.toJSONString(obj[name], depth++);
					} else {
						strJson += ', "' + name + '": "[ TOO DEPTH OBJECT ]"';
					}
				} else {
					strJson += ', "' + name + '": "' + obj[name] + '"';
				}
				
			}
			
			strJson = '{' + strJson.substring(2) + '}';

			return strJson;
		} else if(Snail.isArray(obj)){
			
			for(var name in obj){
				
				if(Snail.isObject([name]) || Snail.isArray(obj[name])){
					if(depth < 100) {
						strJson += ', ' + Snail.toJSONString(obj[name], depth++);
					} else {
						strJson += ', "' + obj[name] + '"';
					}
				} else {
					strJson += ', "[ TOO DEPTH OBJECT ]"';
				}
				
			}
			
			strJson = '[' + strJson.substring(2) + ']';
			
			return strJson;
		}
		/* End */
		
		return Object.prototype.toString.call(obj);
	}, 
	
	/**
	 * 将字符串解析成JSON对象
	 */
	toJSON: function(str){
		
		if(JSON && JSON.parse){
			return JSON.parse(str);
		}
		
		return (new Function("return " + str))(); 
	}, 
	
	/**
	 * 深度克隆
	 */
	deepcopy: function(obj){
		return Snail.toJSON(Snail.toJSONString(obj));
	},
	
	/**
	 * Begin:
	 * 循环执行fn函数，直到fn函数返回true。（或执行fn函数超10次后中断）
	 * 
	 * 样例：
	 * function test(){
	 * 
	 *     var i = Math.random();
	 *     
	 *     alert(i);
	 *     
	 *     if(i > 0.1){
	 *         return false;
	 *     }
	 * 
	 *     alert('执行结束。');
	 * 
	 *     return true;
	 * }
	 * 
	 * Snail.run(test); // 或 Snail.run('test()');
	 */
	__SET_TIMEOUT__: Snail.__SET_TIMEOUT__ || {},
	run: function(fn, fail_fn){
		
		var sleeptimes = Snail.__SET_TIMEOUT__[fn] = (null != Snail.__SET_TIMEOUT__[fn] ? Snail.__SET_TIMEOUT__[fn] : -500);
		
		if((sleeptimes += 500) > 5000){
			
			try {
				
				if(Snail.isString(fail_fn)){
				
					runState = eval(fail_fn);
				
				} else if(Snail.isFunction(fail_fn)){
					
					runState = fail_fn();
				}	
				
			} catch(error){
				alert(error);
			}
			
			Snail.__SET_TIMEOUT__[fn] = 0;
			
			return;
		}
		
		Snail.__SET_TIMEOUT__[fn] = sleeptimes;
		
		window.setTimeout(function(){
			
			var runState = false;
			
			try {
				
				if(Snail.isString(fn)){
				
					runState = eval(fn);
				
				} else if(Snail.isFunction(fn)){
					
					runState = fn();
				}	
				
			} catch(error){
				alert(error);
			}
					
			if(false === runState){
				Snail.run(fn, fail_fn);
			}else{
				Snail.__SET_TIMEOUT__[fn] = 0;
			}
			
		}, sleeptimes);
	},
	/* End */
	
	
	/**
	 * 阻塞
	 * Snail.sleep(2000);
	 */
	sleep: function(num){
		try{
			
			for(var now=new Date().getTime(); (new Date().getTime()-now)<num;){
				;
			}
			
			console.log('阻塞结束...');
		}catch(error){}
	},
	
	
	/**
	 * 将字符串编码成16进值文本
	 */
	encodeHex: function(txt){
		
		if(!txt){
			return txt;
		}
		
		var etxt = "";
		
		for(var i = 0; i < txt.length; i++){
			etxt += "%" + txt.charCodeAt(i).toString(16);
		}
		
		return etxt;
	},
	
	/**
	 * 解码16进值文本
	 */
	decodeHex: function(txt){
		
		if(!txt){
			return txt;
		}
		
		var dtxt = "";
		var arrtxt = txt.split("%");
		
		for(var i = 1; i < arrtxt.length; i++){
			dtxt += String.fromCharCode(parseInt(arrtxt[i], 16));
		}
		
		return dtxt;
	},
	
	/**
	 * byte数组换为字符串  (ASCII)
	 * 	样例：Snail.byteArrayToString([51, 90, 87, 112, 67]);
	 * 		->: 3ZWpC
	 */
	byteArrayToString: function(bytes){
		
		if(null == bytes){
			return;
		}
		
		if(!Snail.isArray(bytes)){
			throw '非byte数组数据！';
		}
		
		var str = '';
		
		for(var i = 0, len = bytes.length; i < len; i++){
			
			var b = bytes[i];
			
			if(!Snail.isNumber(b)){
				throw '非ASCII编码范围内的数组(byte [])数据！(' + b + ')';
			}
			
			if(0 <= b && b < 127){
				str += String.fromCharCode(b);
			}else{
				throw '非ASCII编码范围内(0<=b<127)的数组数据！(无效byte数据：' + b + ')';
			}
		}
		
		return str;
	},
	
	/**
	 * 字符串换为byte数组 (ASCII)
	 * 	样例：Snail.stringToByteArray('3ZWpC');
	 * 		->: [51, 90, 87, 112, 67]
	 */
	stringToByteArray: function(str){
		
		if(null == str){
			return;
		}
				
		var bytes = [];
		
		for(var i=0,len=str.length; i<len; i++){
			
			bytes.push(str.charCodeAt(i))
			
			if(!(0 <= bytes[i] && bytes[i] < 127)){
				throw '非ASCII编码范围内的字符串！(' + str + ')';
			}
		}
		
		return bytes;
	},
	
	/**
	 * byte数组换为16进制字符串
	 * 	样例：Snail.byteArrayToHexString([-74, 90, 87, 112, 67]);
	 * 		->: CA5A577043
	 */
	byteArrayToHexString: function(bytes){
		
		if(null == bytes){
			return;
		}
		
		if(!Snail.isArray(bytes)){
			throw '非byte数组数据！';
		}
		
		var hex = '';
		
		for(var i = 0, len = bytes.length; i < len; i++){
					
			var b = bytes[i];
			
			if(!Snail.isNumber(b)){
				throw '非byte数组数据！(' + b + ')';
			}
			
			if(-128 <= b && b < 0){
				
				hex += ((b * -1) | 0x80).toString(16);
				
			}else if(0 == b){
				
				hex += '00';
				
			}else if(0 < b && b <= 15){
				hex += ('0' + b.toString(16));
			}else if(15 < b && b <= 127){
				hex += b.toString(16);
			}else{
				throw '非byte(-127<b<127)数组数据！(无效byte数据：' + b + ')';
			}
		}
		
		return hex.toUpperCase();
	},
	
	/**
	 * 16进制字符串换为byte数组
	 * 	样例：Snail.hexStringToByteArray('CA5A577043');
	 * 		->: [-74, 90, 87, 112, 67]
	 */
	hexStringToByteArray: function(str){
		
		if(null == str){
			return;
		}
		
		str = str.toLowerCase();
		
		var bytes = [];
		
		for(var i = 0, len = str.length; i < len;){
			
			var b = parseInt(str.substring(i, i+=2), 16);
			
			if(b > 127){ // 负数
				b = ((b & 0x7F) * -1)
			}
			
			bytes.push(b);
		}
		
		return bytes;
	},

	/**
	 * 生成20位随机数
	 */
	random20L: function(){
		
		var now = new Date();
		var yStr = now.getFullYear().toString();
		var mStr = ((now.getMonth() < 9 ? '0' : '') + (now.getMonth() + 1));
		var dStr = ((now.getDate() < 10 ? '0' : '') + now.getDate());
		var hStr = ((now.getHours() < 10 ? '0' : '') + now.getHours());
		var miStr = ((now.getMinutes() < 10 ? '0' : '') + now.getMinutes());
		var sStr = ((now.getSeconds() < 10 ? '0' : '') + now.getSeconds());
		
		var ranStr = Math.random().toString();
		ranStr = '000000' + ranStr.substring(2);
		ranStr = ranStr.substring(ranStr.length - 6);
		
		return yStr + mStr + dStr + hStr + miStr + sStr + ranStr;
	},
	
	/**
	 * 数据转中文大写
	 * 样例：
	 * Snail.numberToUpperCase('8000200021000678') ->    捌仟万零贰仟亿零贰仟壹佰万零陆佰柒拾捌元
	 * Snail.numberToUpperCase('8111200021000678') ->    捌仟壹佰壹拾壹万贰仟亿零贰仟壹佰万零陆佰柒拾捌元
	 * Snail.numberToUpperCase('8555211121987799') ->    捌仟伍佰伍拾伍万贰仟壹佰壹拾壹亿贰仟壹佰玖拾捌万柒仟柒佰玖拾玖元
	 * Snail.numberToUpperCase('8555211121987799.32') -> 捌仟伍佰伍拾伍万贰仟壹佰壹拾壹亿贰仟壹佰玖拾捌万柒仟柒佰玖拾玖元叁角贰分
	 * Snail.numberToUpperCase('8000000000000099') ->    捌仟万亿零玖拾玖元
	 * Snail.numberToUpperCase('8000000000000099.67') -> 捌仟万亿零玖拾玖元陆角柒分
	 * Snail.numberToUpperCase('8000000000000090.67') -> 捌仟万亿零玖拾元陆角柒分
	 * Snail.numberToUpperCase('800000000000') ->    捌仟亿元
	 * Snail.numberToUpperCase('800000000000.56') -> 捌仟亿元伍角陆分
	 * Snail.numberToUpperCase('800000000000.50') -> 捌仟亿元伍角
	 * Snail.numberToUpperCase('800000000000.06') -> 捌仟亿元零陆分
	 * Snail.numberToUpperCase('11121987799.32') ->  壹佰壹拾壹亿贰仟壹佰玖拾捌万柒仟柒佰玖拾玖元叁角贰分
	 * Snail.numberToUpperCase('11121987799.02') ->  壹佰壹拾壹亿贰仟壹佰玖拾捌万柒仟柒佰玖拾玖元零贰分
	 * Snail.numberToUpperCase('11121987799.20') ->  壹佰壹拾壹亿贰仟壹佰玖拾捌万柒仟柒佰玖拾玖元贰角
	 */
	numberToUpperCase: function(num){
		
		if(Snail.isBlank(num)){
			
			return '零';
		}
		
		if(Snail.isNumber(num)){
			num = num.toString();
		}
		
		var index = num.indexOf('.');
		
		if(-1 != index){
		
			if(num.length > index + 3){
				num = num.substring(0, index + 3);
			}
			
			num = num.replace(/\./, '');
			
		}else{
			num += '00';
		}
		
		var len = num.length;
		
		if(len > 18){
			return num + ', 位数过大 !';
		}
		
		num = num.replace(",","") // 去“,”
		num = num.replace(" ","") // 去空格
		
		var num_char = {
			'0': '零', '1': '壹', '2': '贰', '3': '叁', '4': '肆',
			'5': '伍', '6': '陆', '7': '柒', '8': '捌', '9': '玖'
		};
		
		var num_bit = [
			'分', '角', 
			'_元', '拾', '佰', '仟', '_万', '拾', '佰', '仟', 
			'_亿', '拾', '佰', '仟', '_万', '拾', '佰', '仟'
		];
		
		var numStr = '';
		
		for(var i = len; i > 0; i--){
			numStr = num_char[num[i - 1]] + num_bit[len - i] + numStr;
		}
	
		// 去‘_’
		numStr = numStr.replace(/零[_]/g, ''); 
		numStr = numStr.replace(/[_]/g, ''); 

		// 去中部的‘零’
		numStr = numStr.replace(/(零[^零])+/g, '零');
		numStr = numStr.replace(/零亿/g, '亿零');
		numStr = numStr.replace(/零万/g, '万零');
		numStr = numStr.replace(/零+/g, '零');
		numStr = numStr.replace(/零亿/g, '亿');
		numStr = numStr.replace(/零万/g, '万');
		numStr = numStr.replace(/零+元/g, '元');

		// 为亿以上数字时，去尾部的‘万’(多余)
		numStr = numStr.replace(/亿万/g, '亿');
	
		// 去尾部的‘零’
		numStr = (numStr + '_').replace(/零?_/, '');
		
		return numStr;
	},

	/**
	 * 是否为身份证号
	 * 
	 * 样例：Snail.isIdentityCode('123456789012345678')
	 * 
	 * 身份证号码中的校验码是身份证号码的最后一位，是根据GB 11643-1999中有关公民身份号码的规定，根据精密的
	 * 计算公式计算出来的，公民身份号码是特征组合码，由十七位数字本体码和一位数字校验码组成。排列顺序从左至
	 * 右依次为：六位数字地址码，八位数字出生日期码，三位数字顺序码，最后一位是数字校验码。
	 */
	isIdentityCode: function(code){
		
		if(Snail.isBlank(code)){
			return false;
		}
		
		code = code.toUpperCase();
		
		if(!/\d{6}(18|19|20)\d{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01]\d{3}(\d|X))/i.test(code)){ // 身份证号格式错误
			// alert('身份证号格式错误');
			return false;
		}
		
		switch(code.substring(10,12)){
		case '02':{
			
			if(0 == (code.substring(6,10) % 4)){
				
				if(29 < code.substring(12,14)){ // 二月与日不匹配
					// alert('二月与日不匹配');
					return false;
				}
			} else {
				if(28 < code.substring(12,14)){ // 二月与日不匹配
					// alert('二月与日不匹配');
					return false;
				}
			}
			
			break;
		}
		case '04':
		case '06':
		case '09':
		case '11':
			if('31' == code.substring(12,14)){ // 月与日不匹配
				// alert('月与日不匹配');
				return false;
			}
		}
		
		//加权因子
		var factor = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ];
		//校验位
		var parity = [ 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2 ];
		
		var sum = 0;
		
		for(var i = 0; i < 17; i++){
			sum += (factor[i] * code.charAt(i));
		}
		
		var x = sum % 11;
		
		if(parity[x] != code.charAt(17)){ // 校验位错误
			// alert('校验位错误');
			return false;
		}

		return true;
	}
	
});

/* 扩展基本计算 */
Snail.extend('math', function(){
	
	function _plus(num, num2){
		
		var r = 0;
		var r2 = 0; 
		var p = 0;  
		
		var txt = num.toString();
		var i = txt.indexOf('.');
		
		if(-1 != i){
			r = txt.substring(i+1).length;
		}
		
		txt = num2.toString();
		i = txt.indexOf('.');
		
		if(-1 != i){
			r2 = txt.substring(i+1).length;
		}
		
		p = Math.pow(10, Math.max(r, r2));
		
		return (num * p + num2 * p) / p;   
	};
	
	return {
	
		/**
		 * 	加法
		 * 	样例：
		 * 		Snail.math.plus(800, 800.09);
		 */
		'plus': _plus,
		
		/**
		 * 	减法
		 * 	样例：
		 * 		Snail.math.sub(1, 0.9);
		 */
		sub: function(num, num2){ 
			
			return _plus(num, -num2);   
		},
		
		/**
		 * 	乘法
		 * 	样例：
		 * 		Snail.math.mul(1, 0.9);
		 */
		mul: function(num, num2){
			
			var p = 0;
			var txt = num.toString();
			var txt2 = num2.toString();
			
			var i = txt.indexOf('.');
			
			if(-1 != i){
				p += txt.substring(i+1).length;
			}
			
			txt = txt.replace(/\./, '');
			
			i = txt2.indexOf('.');
			
			if(-1 != i){
				p += txt2.substring(i+1).length;
			}

			txt2 = txt2.replace(/\./, '');
			
			p = Math.pow(10, p);
			
			return (parseInt(txt) * parseInt(txt2) / p); 
		},
		
		/**
		 * 	除法
		 * 	样例：
		 * 		Snail.math.div(1, 0.9);
		 */
		div: function(num, num2){
			
			var r = 0;
			var r2 = 0; 
			var p = 0;
			
			var txt = num.toString();
			var i = txt.indexOf('.');
			
			if(-1 != i){
				r = txt.substring(i+1).length;
			}
			
			txt = txt.replace(/\./, '');
			
			var txt2 = num2.toString();
			i = txt2.indexOf('.');
			
			if(-1 != i){
				r2 = txt.substring(i+1).length;
			}

			txt2 = txt2.replace(/\./, '');

			return (parseInt(txt) / parseInt(txt) * pow(10, r2-r));
		}
	};
});

/* 扩展对HTML元素操作 */
Snail.extend({
	
	/**
	 * 选择元素
	 * 	样例：
	 * 		Snail.getElement('#id');
	 * 		Snail.getElement('span', -1);
	 * 		Snail.getElement('#id', 0, window.parent.document);
	 * 		Snail.getElement('span', -1, window.parent.document);
	 */
	getElement: function(selector, index, doc){
		
		if(Snail.isBlank(selector)){
			return;
		}
		
		var eles = (doc || document).querySelectorAll(selector);
		

		if(null == eles || 0 == eles.length){
			
			return;
			
		}else if(1 == eles.length){
			
			return eles[0];
		}
		
		if(Snail.isNumber(index)){
			
			if(0 > index){
				
				index = eles.length + index;
				index = (0 > index ? 0 : index);	
				
			}else{
				
				index = (index >= eles.length ? (eles.length - 1) : index);
			}
			
			return eles[index];
		}
		
		return eles;
	},
	
	/**
	 * 对HTML元素赋值
	 * 	样例：
	 * 		Snail.setEleValue('#id', 'XXX');
	 * 		Snail.setEleValue('span', '文本');
	 */
	setEleValue: function(selector, value){
		
		if(Snail.isBlank(selector)){
			return;
		}
		
		var eles = selector.tagName ? [selector] : document.querySelectorAll(selector);
				
		if(null == eles || 0 == eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			var ele = eles[i];
			
			var key = ele.id || ele.name || ele.tagName;
			
			if('INPUT' == ele.tagName){
				
				if('radio' == ele.type 
					|| 'checkbox' == ele.type){
					
					ele.checked = (value == ele.value);
					
				} else {
					ele.value = value;
				}
				
			}else if('SELECT' == ele.tagName){
				
				var opts = ele.options;
				
				if(ele.multiple){
					vals[key] = [];
				}
				
				for(var j=0, jlen=opts.length; j<jlen; j++){
					
					if(opts[j].selected){
						
						if(ele.multiple){
							vals[key].push(opts[j].value);
						}else{
							vals[key] = opts[j].value;
						}
					}
				}
			}else if('TEXTAREA' == ele.tagName){
				ele.value = value;
			}else{
				ele.innerHTML = value;
			}
		}
	},
	
	/**
	 * 获取HTML元素值
	 * 	样例：
	 * 		Snail.getEleValue('#id');
	 * 		Snail.getEleValue('span');
	 */
	getEleValue: function(selector){
		
		if(Snail.isBlank(selector)){
			return null;
		}
		
		var eles = selector.tagName ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 0 == eles.length){
			return null;
		}
		
		var vals = {};
		var len = eles.length;
		var key = null;
		
		for(var i=0; i<len; i++){
			
			var ele = eles[i];
			
			key = ele.id || ele.name || ele.tagName;
			
			if('INPUT' == ele.tagName){
				
				if('radio' == ele.type){
					
					if(ele.checked){
						vals[key] = ele.value;
					}
					
				} else if('checkbox' == ele.type){
					
					if(ele.checked){
						vals[key] = vals[key] || [];
						vals[key].push(ele.value);
					}
					
				} else {
					vals[key] = ele.value;
				}
				
			}else if('SELECT' == ele.tagName){
				
				var opts = ele.options;
				
				if(ele.multiple){
					vals[key] = [];
				}
				
				for(var j=0, jlen=opts.length; j<jlen; j++){
					
					if(opts[j].selected){
						
						if(ele.multiple){
							vals[key].push(opts[j].value);
						}else{
							vals[key] = opts[j].value;
						}
					}
				}
			}else if('TEXTAREA' == ele.tagName){
				vals[key] = ele.value;
			}else{
				vals[key] = ele.innerHTML;
			}
		}
		
		var size = 0;
		var value = null;
		
		for(var n in vals){
			
			value = vals[n];
			
			size++;
		}
		
		return ((0 == size) ? null : ((1 == size) ? value : vals));
	},
	
	/**
	 * 绑定事件
	 * 	样例：
	 * 		Snail.bindEvent('#id', 'click', fun);
	 * 		Snail.bindEvent('span', 'click', fun);
	 */
	bindEvent: function(selector, event, fun){
		
		if(Snail.isBlank(selector) 
			|| Snail.isBlank(event) 
			|| null == fun
			|| !Snail.isFunction(fun)){
			return ;
		}
		
		var eles = selector.addEventListener ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			var ele = eles[i];
			ele['__snail_cache_events'] = ele['__snail_cache_events'] || []; 
			ele['__snail_cache_eventkeys'] = ele['__snail_cache_eventkeys'] || {}; 
			
			if(!ele['__snail_cache_eventkeys'][fun.toString()]){
				
				ele['__snail_cache_events'].push(fun);
				ele['__snail_cache_eventkeys'][fun.toString()] = true;
				
				ele.addEventListener(event, fun);
			}
		}
	},
	
	/**
	 * 移除事件
	 * 	样例：
	 * 		Snail.removeEvent('span', 'click');
	 */
	removeEvent: function(selector, event){
		
		if(Snail.isBlank(selector) 
			|| Snail.isBlank(event)){
			return ;
		}
		
		var eles = selector.removeEventListener ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			var ele = eles[i];
			var funs = ele['__snail_cache_events'];
			var funkeys = ele['__snail_cache_eventkeys'];
			
			if(null == funs){
				return;	
			}
			
			for(var j=0,jlen=funs.length; j<jlen; j++){
				
				var fun = funs[j];
				
				if(!fun){
					
					funs.splice(j, 1);
					
					j--;
					jlen--;
					
					continue;
				}
				
				if(Snail.isFunction(fun)){
					ele.removeEventListener(event, fun);
				}
				
				funkeys[fun.toString()] = false;
				
				funs.splice(j, 1);
				
				j--;
				jlen--;
			}
		}
	},
	
	/**
	 * 触发事件
	 * 	样例：
	 * 		Snail.onEvent('span', 'click');
	 */
	onEvent: function(selector, event){
		
		if(Snail.isBlank(selector)
			|| Snail.isBlank(event)){
			return ;
		}
		
		var eles = selector.createEvent ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			var ele = eles[i];
			
			var eventObj = ele.createEvent('MouseEvents');
			eventObj.initEvent(event, true, true);
			
			ele.dispatchEvent(eventObj);
		}
	},
	
	/**
	 * 判断HTML的元素是否存在
	 * 	样例：
	 * 		Snail.existHtml('#app');
	 */
	existHtml: function(selector){
		
		if(Snail.isBlank(selector)){
			return false;
		}
		
		var eles = document.querySelectorAll(selector);
		
		if(null != eles && 0 < eles.length){
			return true;
		}
		
		return false;
	},
	
	/**
	 * 在元素内部未尾追加HTML
	 * 	样例：
	 * 		Snail.appendHtml('span', '<span>测试</span>');
	 */
	appendHtml: function(selector, html){
		
		if(Snail.isBlank(selector)
			|| Snail.isBlank(html)){
			return ;
		}
		
		var eles = selector.appendChild ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		var tempEle = document.createElement('div');
		var fragment = document.createDocumentFragment();
		
		tempEle.innerHTML = html;
		
		var nodes = tempEle.childNodes;
		
		for(var i=0, len=nodes.length; i<len; i++){
			fragment.appendChild(nodes[0]);
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			eles[i].appendChild(fragment);
		}
	},
	
	
	/**
	 * 在元素前面插入HTML
	 * 	样例：
	 * 		Snail.insertBeforeHtml('span', '<span>测试</span>');
	 */
	insertBeforeHtml: function(selector, html){
		
		if(Snail.isBlank(selector)
			|| Snail.isBlank(html)){
			return ;
		}
		
		var eles = selector.appendChild ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		var tempEle = document.createElement('div');
		var fragment = document.createDocumentFragment();
		
		tempEle.innerHTML = html;
		
		var nodes = tempEle.childNodes;
		
		for(var i=0, len=nodes.length; i<len; i++){
			fragment.appendChild(nodes[0]);
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			eles[i].parentNode.insertBefore(fragment, eles[i]);
		}
	},
	
	
	/**
	 * 在元素后面插入HTML
	 * 	样例：
	 * 		Snail.insertAfterHtml('span', '<span>测试</span>');
	 */
	insertAfterHtml: function(selector, html){
		
		if(Snail.isBlank(selector)
			|| Snail.isBlank(html)){
			return ;
		}
		
		var eles = selector.appendChild ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		var tempEle = document.createElement('div');
		var fragment = document.createDocumentFragment();
		
		tempEle.innerHTML = html;
		
		var nodes = tempEle.childNodes;
		
		for(var i=0, len=nodes.length; i<len; i++){
			fragment.appendChild(nodes[0]);
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			if(eles[i].parentNode.lastChild == eles[i]){
				eles[i].parentNode.appendChild(fragment);
			}else{
				eles[i].parentNode.insertBefore(fragment, eles[i]);
			}
		}
	},
	
	
	/**
	 * 移除HTML元素
	 * 	样例：
	 * 		Snail.removeHtml('span');
	 */
	removeHtml: function(selector){
		
		if(Snail.isBlank(selector)){
			return ;
		}
		
		var eles = selector.removeChild ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			var ele = eles[i];
			var pele = ele.parentNode;
			pele.removeChild(ele);
		}
	},
	
	/**
	 * 清空HTML元素内部内容
	 * 	样例：
	 * 		Snail.cleanHtml('span');
	 */
	cleanHtml: function(selector){
		
		if(Snail.isBlank(selector)){
			return ;
		}
		
		var eles = selector.innerHTML ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			eles[i].innerHTML = '';
		}
		
	},
	
	/**
	 * 添加CLASS
	 * 	样例：
	 * 		Snail.appendClass('span', 'cls');
	 */
	appendClass: function(selector, className){
		
		
		if(Snail.isBlank(selector)
			|| Snail.isBlank(className)){
			return ;
		}
		
		var eles = selector.getAttribute ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			var cname = eles[i].getAttribute('class');
			
			if(Snail.isBlank(cname)){
				cname = className;
			}else{
				cname += ' ' + className;
			}
			
			eles[i].setAttribute('class', cname);
		}
	},
	
	/**
	 * 移除CLASS
	 * 	样例：
	 * 		Snail.removeClass('span', 'cls');
	 */
	removeClass: function(selector, className){
		
		
		if(Snail.isBlank(selector)
			|| Snail.isBlank(className)){
			return ;
		}
		
		var eles = selector.getAttribute ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			var cname = eles[i].getAttribute('class');
			
			if(Snail.isBlank(cname)){
				continue;
			}else{
				cname = cname.trim();
				
				var index = cname.indexOf(className);
				
				if(0 == index){
					cname = cname.substring(className.length);
				}else if(0 < index){
					cname = cname.replace(new RegExp('\\s' + className, 'g'), '');
				}
			}
			
			eles[i].setAttribute('class', cname);
		}
	},
	
	/**
	 * 设置CSS
	 * 	样例：
	 * 		Snail.setCSS('span', {'background-color': '#ffffff'});
	 */
	setCSS: function(selector, css){
		
		
		if(Snail.isBlank(selector) || !Snail.isObject(css)){
			return ;
		}
		
		var eles = selector.getAttribute ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			var style = eles[i].getAttribute('style');
			
			if(Snail.isBlank(style)){
				style = '';
			}else{
				style = style.trim();
			}

			style = style.split(';');

			var newStyle = {};

			for(var j=0,jlen=style.length; j<jlen; j++){

				var tempStyle = style[j].trim();
				tempStyle = tempStyle.split(':');
				
				if(2 == tempStyle.length){
					newStyle[tempStyle[0].trim()] = tempStyle[1].trim();
				}
			}
			
			for(var n in css){
				newStyle[n] = css[n];
			}

			var newStyleStr = [];

			for(var n in newStyle){
				newStyleStr.push(n + ': ' + newStyle[n] + ';');
			}
			
			eles[i].setAttribute('style', newStyleStr.join(' '));
		}
	},
	
	/**
	 * 创建Style
	 * 
	 * 	样例：
	 * 		Snail.createStyle('span', {'background-color': '#ffffff'});
	 */
	createStyle: function(selector, css){
		
		var styleStr = [selector];
		styleStr.push('{');
		
		for(var n in css){
			styleStr.push(n + ': ' + css[n] + '; ');
		}
		
		styleStr.push('}');
		
		var style = document.createElement('style');
		style.type = 'text/css';
		style.innerHTML = styleStr.join('');
		
		document.getElementsByTagName('head').item(0).appendChild(style);
	},
	
	/**
	 * 设置属性
	 * 	样例：
	 * 		Snail.setEleAttribute('span', {'title': '标题'});
	 */
	setEleAttribute: function(selector, attr){
		
		
		if(Snail.isBlank(selector) || !Snail.isObject(attr)){
			return ;
		}
		
		var eles = selector.getAttribute ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			for(var n in attr){
				eles[i].setAttribute(n, attr[n]);	
			}
		}
	},
	
	/**
	 *	调用Element方法
	 * 	样例：
	 * 		Snail.callEleMethod('span', 'focus');
	 * 		Snail.callEleMethod('span', 'setAttribute', function(method, ele, index, size){
	 * 			if(0 == index){
	 * 				method('style', 'color: #ff0022;');
	 * 			}
	 * 		});
	 */
	callEleMethod: function(selector, method, fn){
		
		
		if(Snail.isBlank(selector) || Snail.isBlank(method)){
			return ;
		}
		
		var eles = selector[method] ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return;
		}
		
		for(var i=0, len=eles.length; i<len; i++){
			
			if(fn){
				fn(eles[i][method], eles[i], i, len);
			}else{
				eles[i][method]();
			}
		}
	},
	
	/**
	 *	获取元素（Element）的X坐标
	 * 	样例：
	 * 		Snail.getEleLeft('#ele');
	 */
	 getEleLeft: function(selector){
		
		
		if(Snail.isBlank(selector)){
			return 0;
		}
		
		var eles = Snail.isHTMLElement(selector) ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return 0;
		}
		
		var xs = [];

		for(var i=0, len=eles.length; i<len; i++){
			
			xs.push(eles[i].offsetLeft);

			var pEle = eles[i].offsetParent;

			while(null != pEle){

				xs[i] += pEle.offsetLeft;

				pEle = pEle.offsetParent;
			}
		}

		return 1 < xs.length ? xs : xs[0];
	},
	
	/**
	 *	获取元素（Element）的Y坐标
	 * 	样例：
	 * 		Snail.getEleLeft('#ele');
	 */
	 getEleTop: function(selector){
		
		
		if(Snail.isBlank(selector)){
			return 0;
		}
		
		var eles = Snail.isHTMLElement(selector) ? [selector] : document.querySelectorAll(selector);
		
		if(null == eles || 1 > eles.length){
			return 0;
		}
		
		var ys = [];

		for(var i=0, len=eles.length; i<len; i++){
			
			ys.push(eles[i].offsetTop);

			var pEle = eles[i].offsetParent;

			while(null != pEle){

				ys[i] += pEle.offsetTop;

				pEle = pEle.offsetParent;
			}
		}

		return 1 < ys.length ? ys : ys[0];
	}
});


Snail.extend('http', function(){
	
	function _ajax(url_or_obj, method, data, header, onsuccess, onerror, oncomplete){

		if(Snail.isObject(url_or_obj)){
							
			return _http(
				url_or_obj.url, url_or_obj.method || method, url_or_obj.data, url_or_obj.header, 
				url_or_obj.onsuccess, url_or_obj.onerror, url_or_obj.oncomplete
			);
			
		}
			
		return _http(url_or_obj, method, data, header, onsuccess, onerror, oncomplete);
	}
		
	function _http(url, method, data, headers, onsuccess, onerror, oncomplete){
				
		var xhr = new XMLHttpRequest();
		var isAsync = false;
		var isJsonResponse = false;
		var agency = null;
		
		
		if('GET' == method.toUpperCase()){
		
			if(data && Snail.isObject(data)){
				
				for(var n in data){
					
					url = Snail.request.join(url, n, data[n]);
				}
			}
			
			data = null;
		}
		
		if(null == headers || !Snail.isObject(headers)){
			
			headers = {
				'Content-Type': 'application/x-www-form-urlencoded',
				'Accept': 'text/xml'
			};
		}
		
		var isDataModify = false;
		var hasContentType = false;
		var hasAccept = false;
			
		for(var n in headers){
			
			if('content-type' == n.toLowerCase() && false == isDataModify){
				
				if(-1 != headers[n].toLowerCase().indexOf('json')){
											
					if(data && Snail.isObject(data)){
						
						data = Snail.toJSONString(data);
						
						isDataModify = true;
					}
					
				}else if(-1 != headers[n].toLowerCase().indexOf('x-www-form-urlencoded')){
					
					if(data && Snail.isObject(data)){
						
						var newData = '';
						
						for(var n in data){
							
							newData += ('&' + n + '=' + (data[n] ? encodeURIComponent(data[n].toString()) : ''));
						}
						
						data = newData.substring(1);
						
						isDataModify = true;
					}
					
				}else{
					
					if(data && Snail.isObject(data)){
						
						var newData = new FormData();
					
						for(var n in data){
							newData.append(n, data[n]);
						}
						
						data = newData;
						
						isDataModify = true;
					}
				}
				
				hasContentType = true;
				
			}else if('accept' == n.toLowerCase()){
				
				if(-1 != headers[n].toLowerCase().indexOf('json')){
					isJsonResponse = true;
				}
				
				hasAccept = true;
				
			}else if('agency' == n.toLowerCase()){
				agency = headers[n];
			}
		}
					
		if(!hasContentType){
			
			headers['Content-Type'] = 'application/x-www-form-urlencoded';
			
			if(data && Snail.isObject(data)){
						
				var newData = '';
				
				for(var n in data){
					
					newData += ('&' + n + '=' + (data[n] ? encodeURIComponent(data[n].toString()) : ''));
				}
				
				data = newData.substring(1);
				
				isDataModify = true;
			}
		}
		
		if(!hasAccept){
			
			headers['Accept'] = 'text/xml';
		}
			
		
		if(null == onsuccess && null == onerror && null == oncomplete){
			
			xhr.open(method, (agency || url), false);
			
		}else{
			
			xhr.onreadystatechange = function(){
				
				if(1 == xhr.readyState){
					// open() 方法已调用，但是 send() 方法未调用。请求还没有被发送。
				}else if(2 == xhr.readyState){
					// Send() 方法已调用，HTTP 请求已发送到 Web 服务器。未接收到响应。
				}else if(3 == xhr.readyState){
					// 所有响应头部都已经接收到。响应体开始接收但未完成。
				}else if(4 == xhr.readyState){
					// HTTP 响应已经完全接收
					
					if(200 <= xhr.status && xhr.status <= 299){
						onsuccess && onsuccess(
							(isJsonResponse ? Snail.toJSON(xhr.responseText) : xhr.responseText), 
							xhr.status, 
							xhr
						);
					}else{
						onerror && onerror(xhr.responseText, xhr.status, xhr);
					}
					
					oncomplete && oncomplete(xhr.responseText, xhr.status, xhr);
				}
			}
			
			isAsync = true;
			xhr.open(method, (agency || url), true);
		}
				
		if(Snail.isObject(headers)){
						
			for(var n in headers){
				
				if('agency' == n.toLowerCase()){
					continue;
				}
				
				xhr.setRequestHeader(n, headers[n]);
			}
			
			if(agency){
				xhr.setRequestHeader('Agency-Target-Url', url);
			}
		}
		
		if(!Snail.isBlank(data)){
			
			xhr.send(data);
			
		}else{
			xhr.send();
		}
		
		if(isAsync){
			return null;
		}
		
		if(isJsonResponse){
			return Snail.toJSON(xhr.responseText);
		}
		
		return xhr.responseText;
    }
	
	function _upload2(url_or_obj, file, header,
					onloadstart, onprogress, onloadend, onsuccess, onerror, oncomplete){
	
		if(Snail.isObject(url_or_obj)){
							
			return _upload(url_or_obj.url, url_or_obj.file, url_or_obj.header,
					url_or_obj.onloadstart, url_or_obj.onprogress, url_or_obj.onloadend, 
					url_or_obj.onsuccess, url_or_obj.onerror, url_or_obj.oncomplete
			);
			
		}
			
		return _upload(url_or_obj, file, header,
				onloadstart, onprogress, onloadend, onsuccess, onerror, oncomplete);
		
	}
	
	function _upload(url, file, header,
					onloadstart, onprogress, onloadend, onsuccess, onerror, oncomplete){
		
		var formData = new FormData();
		formData.append('file', file);

		var xhr = new XMLHttpRequest();
		var isAsync = false;
		
		if(null == onsuccess && null == onerror && null == oncomplete){
			
			xhr.open('POST', url, false);
			
		}else{
			
			xhr.onreadystatechange = function(){
				
				if(1 == xhr.readyState){
					// open() 方法已调用，但是 send() 方法未调用。请求还没有被发送。
				}else if(2 == xhr.readyState){
					// Send() 方法已调用，HTTP 请求已发送到 Web 服务器。未接收到响应。
				}else if(3 == xhr.readyState){
					// 所有响应头部都已经接收到。响应体开始接收但未完成。
				}else if(4 == xhr.readyState){
					// HTTP 响应已经完全接收
					if(200 <= xhr.status && xhr.status <= 299){
						onsuccess && onsuccess(xhr.responseText, xhr.status, xhr);
					}else{
						onerror && onerror(xhr.responseText, xhr.status, xhr);
					}
					
					oncomplete && oncomplete(xhr.responseText, xhr.status, xhr);
				}
			}
			
			isAsync = true;
			xhr.open('POST', url, true);
		}
		
		if(Snail.isObject(header)){
						
			for(var n in header){
				xhr.setRequestHeader(n, header[n]);
			}
		}
		
		onloadstart && (xhr.upload.onloadstart = onloadstart);
		onprogress && (xhr.upload.onprogress = onprogress);
		onloadend && (xhr.upload.onloadend = onloadend);
		
		xhr.send(formData);
		
		if(isAsync){
			return null;
		}
		
		return xhr.responseText;
	}

    return {
		
		/**
		 * AJAX简单实现
		 * 
		 * 样例：
		 * 	Snail.http.ajax('http://www.xxx.com/si?p=x', 'GET');
		 *  Snail.http.ajax({url: 'http://www.xxx.com/si?p=x', method:'GET'});
		 *  Snail.http.ajax({url: 'http://www.xxx.com/si?p=x', method:'GET', data: {'key': 'value'}});
		 * 
		 * 	常见Content-Type:
		 * 		application/x-www-form-urlencoded | application/json | application/json; charset=UTF-8 | text/html
		 * 	
		 * 	Snail.http.ajax('http://www.xxx.com/si?p=x', 'POST', {'key': 'value'}, 
		 *  	{'Content-Type': 'application/json', 'Accept': 'application/json'}, 
		 *  	function(responseText/{json object}, status, xhr){}, // onsuccess
		 *  	function(responseText, status, xhr){}, // onerror
		 * 		function(responseText, status, xhr){} // oncomplete
		 *  );
		 * 
		 *  Snail.http.ajax({url: 'http://www.xxx.com/si?p=x', method:'POST', data: {'key': 'value'}});
		 * 
		 *  Snail.http.ajax({
		 *  	url: 'http://www.xxx.com/si?p=x', 
		 *  	method:'POST', 
		 *  	data: {'key': 'value'}, 
		 *  	header:{'Content-Type': 'application/json', 'Accept': 'application/json'}
		 *  });
		 * 
		 *  Snail.http.ajax({
		 *  	url: 'http://www.xxx.com/si?p=x', 
		 *  	method:'POST', 
		 *  	data: {'key': 'value'}, 
		 *  	header:{'Content-Type': 'application/json', 'Accept': 'application/json'},
		 *  	onsuccess: function(responseText/{json object}, status, xhr){},
		 *  	onerror: function(responseText, status, xhr){},
		 * 		oncomplete: function(responseText, status, xhr){}
		 *  });
		 */
        ajax: function(url_or_obj, method, data, header, onsuccess, onerror, oncomplete){
				
			return _ajax(url_or_obj, method, data, header, onsuccess, onerror, oncomplete);
		},
		
			
		/**
		 * AJAX简单实现
		 * 
		 * 样例：
		 * 	Snail.http.get('http://www.xxx.com/si?p=x');
		 *  Snail.http.get({url: 'http://www.xxx.com/si?p=x', data: {'key': 'value'}});
		 */
		get: function(url_or_obj, data, header, onsuccess, onerror, oncomplete){
			
			if(Snail.isObject(url_or_obj)){
				
				if(url_or_obj.data && Snail.isObject(url_or_obj.data)){
					
					for(var n in url_or_obj.data){
						url_or_obj.url = Snail.request.join(url_or_obj.url, n, url_or_obj.data[n]);
					}
					
					url_or_obj.data = null;
				}
		
			}else{
				
				if(data && Snail.isObject(data)){
					for(var n in data){
						url_or_obj = Snail.request.join(url_or_obj, n, data[n]);
					}
				}
			}
			
			return _ajax(url_or_obj, 'GET', null, header, onsuccess, onerror, oncomplete);
		},
		
		
		post: function(url_or_obj, data, header, onsuccess, onerror, oncomplete){			
			return _ajax(url_or_obj, 'POST', data, header, onsuccess, onerror, oncomplete);
		},
		
		put: function(url_or_obj, data, header, onsuccess, onerror, oncomplete){			
			return _ajax(url_or_obj, 'PUT', data, header, onsuccess, onerror, oncomplete);
		},
		
		delete: function(url_or_obj, data, header, onsuccess, onerror, oncomplete){			
			return _ajax(url_or_obj, 'DELETE', data, header, onsuccess, onerror, oncomplete);
		},

		/**
		 * 执行请求队列
		 * 
		 * 样例：
		 * 
		 *  Snail.http.ajaxList([{
		 *  	url: 'http://www.xxx.com/req1?p=x', 
		 *  	method:'GET', 
		 *  	data: {'key': 'value'}, 
		 *  	header:{'Content-Type': 'application/json', 'Accept': 'application/json'},
		 *  	onsuccess: function(responseText/{json object}, status, xhr){},
		 *  	onerror: function(responseText, status, xhr){},
		 * 		oncomplete: function(responseText, status, xhr){
		 *
		 * 			// 返回1（或0、或不返回任何值）则进入一下ajax请求，返2则进入下下一个ajax请求，返回-1则进入前一个ajax请求，返回-2则进入前两个ajax请求，其它，依此类推
		 *			return 1;
		 * 		}
		 *  },{
		 *  	url: 'http://www.xxx.com/req2?p=x2', 
		 *  	method:'POST', 
		 *  	data: {'key': 'value'}, 
		 *  	header:{'Content-Type': 'application/json', 'Accept': 'application/json'},
		 *  	onsuccess: function(responseText/{json object}, status, xhr){},
		 *  	onerror: function(responseText, status, xhr){},
		 * 		oncomplete: function(responseText, status, xhr){}
		 *  }]);
		 */
		ajaxList: function(requestList){

			if(!requestList || 0 == requestList.length){
				return ;
			}

			(Snail._http_callbacks = function(index){

				if(index >= requestList.length){
					return;
				}

				var req = requestList[index];
				
				if(!req){
					return;
				}

				_ajax(
					req.url, 
					(req.method || 'GET'), 
					req.data, 
					req.header, 
					function(data, status, xhr){
						req.onsuccess && req.onsuccess(data, status, xhr);
					}, 
					function(responseText, status, xhr){
						req.onerror && req.onerror(responseText, status, xhr);
					}, 
					function(responseText, status, xhr){

						var stepSize = 1;
						
						if(req.oncomplete){
							stepSize = req.oncomplete(responseText, status, xhr);
						}
						
						if(!stepSize || 0 == stepSize){
							
							stepSize = 1;
							
						}else{
							stepSize = Snail.isNumber(stepSize) ? stepSize : 1;
						}			
						
						
						Snail._http_callbacks(index + stepSize);
					}
				);

			})(0);

		},
		
		/**
		 * 简单文件上传实现
		 * 
		 * 样例：
		 *  Snail.http.upload('http://www.xxx.com/upload/file?p=x', {FileUpload});
		 *  Snail.http.upload('http://www.xxx.com/upload/file?p=x', {FileUpload}, 
		 *  	{'Content-Type': 'multipart/form-data', 'Accept': 'application/json'}, 
		 *  	function(event){}, // onloadstart
		 *  	function(event){}, // onprogress
		 *  	function(event){}, // onloadend
		 *  	function(responseText, status, xhr){}, // onsuccess
		 *  	function(responseText, status, xhr){}  // onerror
		 * 		function(responseText, status, xhr){}  // oncomplete
		 *  );
		 * 
		 *  Snail.http.upload({
		 *  	url: 'http://www.xxx.com/upload/file?p=x', 
		 *  	file: {FileUpload}, 
		 *  	header:{'Content-Type': 'multipart/form-data', 'Accept': 'application/json'},
		 *  	onloadstart: function(event){},
		 *  	onprogress: function(event){
		 *			// event.total是需要传输的总字节
		 *  		// event.loaded是已经传输的字节
		 *  	},
		 *  	onloadend: function(event){},
		 *  	onsuccess: function(responseText, status, xhr){},
		 *  	onerror: function(responseText, status, xhr){},
		 *  	oncomplete: function(responseText, status, xhr){}
		 *  });
		 */
		upload: _upload2
    }
});


/* 扩展对Cookie的操作 */ 
Snail.extend('cookie', {
	

	getCookie: function(key){
		
		var startIndex = 0;
		var endIndex = 0;
		
		if (document.cookie.length > 0){
			
			startIndex = document.cookie.indexOf(key + "=");
			
			if (startIndex != -1) {
			
				startIndex = startIndex + key.length + 1;
				endIndex = document.cookie.indexOf(";", startIndex);
				
				if(endIndex == -1){
					endIndex = document.cookie.length;
				}
		
				return  startIndex == endIndex ? null : unescape(document.cookie.substring(startIndex, endIndex));
			}
		}

		return null;
	},
	
	/**
	 * 添加Cookie
	 * 
	 * 样例：
	 * 	Snail.setCookie('skey', '12345678');
	 * 	Snail.setCookie('skey', '12345678', (365 * 24 * 60 * 60 * 1000));
	 * 	Snail.setCookie('skey', '12345678', {expires: (365 * 24 * 60 * 60 * 1000), path: '/', domain:'snail.com', secure: true });
	 * 	Snail.setCookie('skey', '12345678', 'expires=Wed, 29 Aug 2018 00:27:38 GMT; path=/; domain=snail.com, secure=true');
	 */
	setCookie: function (key, value) {
		
		var txt = (key + "=" + escape(Snail.isObject(value) ? Snail.toJSONString(value) : value));
		
		if(2 == arguments.length){
			
			var expiredays = new Date();
			expiredays.setTime(expiredays.getTime() + (24 * 60 * 60 * 1000));
			
			txt += ('; expires=' + expiredays.toGMTString());
			txt += '; path=/';
			
		} else if(3 == arguments.length){
			
			if(Snail.isNumber(arguments[2])){
				
				var expiredays = new Date();
				expiredays.setTime(expiredays.getTime() + arguments[2]);
				
				txt += ('; expires=' + expiredays.toGMTString());
				txt += '; path=/';
				
			} else if(Snail.isObject(arguments[2])){
				
				var val = null;
				
				for(var name in arguments[2]){
					
					val = arguments[2][name];
					
					if('expires' === name){
						
						var expiredays = new Date();
						expiredays.setTime(expiredays.getTime() + (Snail.isNumber(val) ? val : new Number(val)));
						
						txt += ('; expires=' + expiredays.toGMTString());
					} else {
						txt += ('; ' + name + '=' + val);
					}
				}
			} else {
				txt += ('; ' + arguments[2]);
			}	
			
		} 
		
				
		document.cookie = txt;
	},
	
	delCookie: function (key) {
		
		var value = getCookie(key);
		
		if(null == value || "" == value){
			return;
		}
		
		var expiredays = new Date();
		expiredays.setDate(expiredays.getDate() - 1);
		
		document.cookie = key + "=" + escape(value) + ";expires=" + expiredays.toGMTString();
		
		return value;
	}
});



/* 扩展对HTTP请求（request）的操作 */ 
Snail.extend('request', {

	/**
	 * 从URL中提取数据
	 * 样例：
	 * 		URL: http://www.i8yun.com/app?name=snail&code=S001
	 * 		
	 * 		Snail.request.getParament('code');
	 * 			-> S001
	 * 
	 */
	getParament: function (key, defaultValue){
		
		var url = window.location.href;
		
		var si = -1, ei = -1;
		
		si = url.indexOf(key + "=");
		
		if (si != -1) {
			
			si = si + key.length + 1;
			
			ei = url.indexOf("&", si);
			
			if(ei == -1){
				ei = url.length;
			}
			
			return url.substring(si, ei);
		}
		
		return defaultValue;
	},
	
	/**
	 * 从URL中提取数据
	 * 样例：
	 * 		URL: http://www.i8yun.com/app?name=snail&code=S001
	 * 		
	 * 		Snail.request.getParaments();
	 * 			-> {"name": "snail", "code": "S001"}
	 * 
	 */
	getParaments: function(){
		
		var href = window.location.href;
		var index = href.indexOf('?');

		if(-1 == index){
			return null;
		}

		var search = window.location.href.substring(index + 1);
		
		if(Snail.isBlank(search)){
			return null;
		}

		var paramentObj = {};
		var paraments = search.split('&');

		for(var i=0,len=paraments.length; i<len; i++){

			index = paraments[i].indexOf('=');
			
			if(-1 == index){
				paramentObj[i.toString()] = paraments[i];
			}else{
				paramentObj[paraments[i].substring(0, index)] = paraments[i].substring(index + 1);
			}
		}
		
		return  paramentObj;
	},
	
	/* 返回：http://172.16.0.234:8080 */
	getHostUrl: function(){
		return Snail.request.getProtocol() + '://' + Snail.request.getHost() + ':' + Snail.request.getPort();
	},
	
	/* 返回：http */
	getProtocol: function (){
		return window.location.protocol.substring(0, (window.location.protocol.length - 1));
	},
	
	/* 返回：172.16.0.234 */
	getHost: function (){
		return window.location.hostname;
	},
	
	/* 返回：8080 */
	getPort: function (){
		return window.location.port ? window.location.port : ('https' === Snail.request.getProtocol() ? '443' : '80');
	},
	
	/**
	 * 拼接URL
	 * 样例：
	 * 		Snail.request.join('code', 'S001');
	 * 			-> http://www.i8yun.com/app?code=S001
	 * 		Snail.request.join('http://www.i8yun.com/app?name=snail', 'code', 'S001');
	 * 			-> http://www.i8yun.com/app?name=snail&code=S001
	 */
	join: function (){
		
		var url = null;
		var key = null;
		var value = null;
		
		if(2 == arguments.length){
			url = window.location.href;
			key = arguments[0];
			value = arguments[1];
		} else if(3 == arguments.length){
			url = arguments[0];
			key = arguments[1];
			value = arguments[2];
		}else{
			return null;
		}
		
		return url + (-1 == url.indexOf('?') ? '?' : '&') + key + '=' + encodeURIComponent(value);
	}
});


/* 扩展对数组的操作 */ 
Snail.extend('list', {

	/**
	 * 对数组进行过滤（默认去重）
	 * 样例：
	 * 		Snail.list.filter([1, 1, 3, 1, 2, 3]);
	 * 			-> [1, 3, 2]
	 * 
	 */
	filter: function (list, fn){

		if(!list || 1 > list.length){
			return list;
		}

		if(!fn){
			var _list_cache = [];
			
			fn = function(val, index){

				for(var i=0,len=_list_cache.length; i<len; i++){
					if(val === _list_cache[i]){
						return false;
					}
				}
				
				_list_cache.push(val);

				return true;
			};
		}

		var tempList = [];

		for(var i=0,len=list.length; i<len; i++){

			if(fn(list[i], i)){
				tempList.push(list[i]);
			}
		}

		return tempList;
	},
	
	/**
	 * 对数组进行排序
	 * 样例：
	 * 		Snail.list.filter([1, 1, 3, 1, 2, 3]);
	 * 			-> [1, 1, 1, 2, 3, 3]
	 * 
	 */
	sort: function(list, fn){

		if(!list || 1 > list.length){
			return list;
		}

		if(!fn){
			fn = function(val, nextVal){
				return ((val>nextVal) ? 1 : ((val==nextVal) ? 0 : -1));
			};
		}

		for(var i=0,len=list.length; i<len; i++){
			for(var j=i+1; j<len; j++){

				if(0 < fn(list[i], list[j])){
					var tempVal = list[i];
					list[i] = list[j];
					list[j] = tempVal;
				}
			}
		}

		return list;
	},
	
	/**
	 * 是否包含
	 * 
	 * 样例：
	 * 		Snail.list.contain(5, [1, 1, 3, 1, 2, 3]);
	 * 			-> false;
	 * 
	 */
	contain: function(obj, list, fn){

		if(!list || 1 > list.length){
			return false;
		}

		if(!fn){
			fn = function(obj){
				return obj;
			};
		}

		for(var i=0,len=list.length; i<len; i++){
			
			if(obj === fn(list[i])){
				return true;
			}
		}

		return false;
	}
});


/**
 *  基于第三方MD5工具封装 
 *  
 *  样例：
 *  Snail.hex_md5('ASDFGHJKL') 						-> a125f852854bff5d6d876183b1a2562c
 *  Snail.hex_hmac_md5('ASDFGHJKL','123456') 		-> e79cd0e9f528c32b28e5d06b8f57427c
 *  Snail.base64_md5('ASDFGHJKL') 					-> oSX4UoVL/11th2GDsaJWLA
 *  Snail.base64_hmac_md5('ASDFGHJKL','123456') 	-> 55zQ6fUowyso5dBrj1dCfA
 */
Snail.extend(function(){
	
	/*
	 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
	 * Digest Algorithm, as defined in RFC 1321.
	 * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
	 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
	 * Distributed under the BSD License
	 * See http://pajhome.org.uk/crypt/md5 for more info.
	 */
	var hexcase=0;var b64pad="";var chrsz=8;function hex_md5(a){return binl2hex(core_md5(str2binl(a),a.length*chrsz))}function b64_md5(a){return binl2b64(core_md5(str2binl(a),a.length*chrsz))}function str_md5(a){return binl2str(core_md5(str2binl(a),a.length*chrsz))}function hex_hmac_md5(a,b){return binl2hex(core_hmac_md5(a,b))}function b64_hmac_md5(a,b){return binl2b64(core_hmac_md5(a,b))}function str_hmac_md5(a,b){return binl2str(core_hmac_md5(a,b))}function core_md5(p,k){p[k>>5]|=128<<((k)%32);p[(((k+64)>>>9)<<4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g<p.length;g+=16){var j=o;var h=n;var f=m;var e=l;o=md5_ff(o,n,m,l,p[g+0],7,-680876936);l=md5_ff(l,o,n,m,p[g+1],12,-389564586);m=md5_ff(m,l,o,n,p[g+2],17,606105819);n=md5_ff(n,m,l,o,p[g+3],22,-1044525330);o=md5_ff(o,n,m,l,p[g+4],7,-176418897);l=md5_ff(l,o,n,m,p[g+5],12,1200080426);m=md5_ff(m,l,o,n,p[g+6],17,-1473231341);n=md5_ff(n,m,l,o,p[g+7],22,-45705983);o=md5_ff(o,n,m,l,p[g+8],7,1770035416);l=md5_ff(l,o,n,m,p[g+9],12,-1958414417);m=md5_ff(m,l,o,n,p[g+10],17,-42063);n=md5_ff(n,m,l,o,p[g+11],22,-1990404162);o=md5_ff(o,n,m,l,p[g+12],7,1804603682);l=md5_ff(l,o,n,m,p[g+13],12,-40341101);m=md5_ff(m,l,o,n,p[g+14],17,-1502002290);n=md5_ff(n,m,l,o,p[g+15],22,1236535329);o=md5_gg(o,n,m,l,p[g+1],5,-165796510);l=md5_gg(l,o,n,m,p[g+6],9,-1069501632);m=md5_gg(m,l,o,n,p[g+11],14,643717713);n=md5_gg(n,m,l,o,p[g+0],20,-373897302);o=md5_gg(o,n,m,l,p[g+5],5,-701558691);l=md5_gg(l,o,n,m,p[g+10],9,38016083);m=md5_gg(m,l,o,n,p[g+15],14,-660478335);n=md5_gg(n,m,l,o,p[g+4],20,-405537848);o=md5_gg(o,n,m,l,p[g+9],5,568446438);l=md5_gg(l,o,n,m,p[g+14],9,-1019803690);m=md5_gg(m,l,o,n,p[g+3],14,-187363961);n=md5_gg(n,m,l,o,p[g+8],20,1163531501);o=md5_gg(o,n,m,l,p[g+13],5,-1444681467);l=md5_gg(l,o,n,m,p[g+2],9,-51403784);m=md5_gg(m,l,o,n,p[g+7],14,1735328473);n=md5_gg(n,m,l,o,p[g+12],20,-1926607734);o=md5_hh(o,n,m,l,p[g+5],4,-378558);l=md5_hh(l,o,n,m,p[g+8],11,-2022574463);m=md5_hh(m,l,o,n,p[g+11],16,1839030562);n=md5_hh(n,m,l,o,p[g+14],23,-35309556);o=md5_hh(o,n,m,l,p[g+1],4,-1530992060);l=md5_hh(l,o,n,m,p[g+4],11,1272893353);m=md5_hh(m,l,o,n,p[g+7],16,-155497632);n=md5_hh(n,m,l,o,p[g+10],23,-1094730640);o=md5_hh(o,n,m,l,p[g+13],4,681279174);l=md5_hh(l,o,n,m,p[g+0],11,-358537222);m=md5_hh(m,l,o,n,p[g+3],16,-722521979);n=md5_hh(n,m,l,o,p[g+6],23,76029189);o=md5_hh(o,n,m,l,p[g+9],4,-640364487);l=md5_hh(l,o,n,m,p[g+12],11,-421815835);m=md5_hh(m,l,o,n,p[g+15],16,530742520);n=md5_hh(n,m,l,o,p[g+2],23,-995338651);o=md5_ii(o,n,m,l,p[g+0],6,-198630844);l=md5_ii(l,o,n,m,p[g+7],10,1126891415);m=md5_ii(m,l,o,n,p[g+14],15,-1416354905);n=md5_ii(n,m,l,o,p[g+5],21,-57434055);o=md5_ii(o,n,m,l,p[g+12],6,1700485571);l=md5_ii(l,o,n,m,p[g+3],10,-1894986606);m=md5_ii(m,l,o,n,p[g+10],15,-1051523);n=md5_ii(n,m,l,o,p[g+1],21,-2054922799);o=md5_ii(o,n,m,l,p[g+8],6,1873313359);l=md5_ii(l,o,n,m,p[g+15],10,-30611744);m=md5_ii(m,l,o,n,p[g+6],15,-1560198380);n=md5_ii(n,m,l,o,p[g+13],21,1309151649);o=md5_ii(o,n,m,l,p[g+4],6,-145523070);l=md5_ii(l,o,n,m,p[g+11],10,-1120210379);m=md5_ii(m,l,o,n,p[g+2],15,718787259);n=md5_ii(n,m,l,o,p[g+9],21,-343485551);o=safe_add(o,j);n=safe_add(n,h);m=safe_add(m,f);l=safe_add(l,e)}return Array(o,n,m,l)}function md5_cmn(h,e,d,c,g,f){return safe_add(bit_rol(safe_add(safe_add(e,h),safe_add(c,f)),g),d)}function md5_ff(g,f,k,j,e,i,h){return md5_cmn((f&k)|((~f)&j),g,f,e,i,h)}function md5_gg(g,f,k,j,e,i,h){return md5_cmn((f&j)|(k&(~j)),g,f,e,i,h)}function md5_hh(g,f,k,j,e,i,h){return md5_cmn(f^k^j,g,f,e,i,h)}function md5_ii(g,f,k,j,e,i,h){return md5_cmn(k^(f|(~j)),g,f,e,i,h)}function core_hmac_md5(c,f){var e=str2binl(c);if(e.length>16){e=core_md5(e,c.length*chrsz)}var a=Array(16),d=Array(16);for(var b=0;b<16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=core_md5(a.concat(str2binl(f)),512+f.length*chrsz);return core_md5(d.concat(g),512+128)}function safe_add(a,d){var c=(a&65535)+(d&65535);var b=(a>>16)+(d>>16)+(c>>16);return(b<<16)|(c&65535)}function bit_rol(a,b){return(a<<b)|(a>>>(32-b))}function str2binl(d){var c=Array();var a=(1<<chrsz)-1;for(var b=0;b<d.length*chrsz;b+=chrsz){c[b>>5]|=(d.charCodeAt(b/chrsz)&a)<<(b%32)}return c}function binl2str(c){var d="";var a=(1<<chrsz)-1;for(var b=0;b<c.length*32;b+=chrsz){d+=String.fromCharCode((c[b>>5]>>>(b%32))&a)}return d}function binl2hex(c){var b=hexcase?"0123456789ABCDEF":"0123456789abcdef";var d="";for(var a=0;a<c.length*4;a++){d+=b.charAt((c[a>>2]>>((a%4)*8+4))&15)+b.charAt((c[a>>2]>>((a%4)*8))&15)}return d}function binl2b64(d){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var f="";for(var b=0;b<d.length*4;b+=3){var e=(((d[b>>2]>>8*(b%4))&255)<<16)|(((d[b+1>>2]>>8*((b+1)%4))&255)<<8)|((d[b+2>>2]>>8*((b+2)%4))&255);for(var a=0;a<4;a++){if(b*8+a*6>d.length*32){f+=b64pad}else{f+=c.charAt((e>>6*(3-a))&63)}}}return f};

	return {
		hex_md5: hex_md5,
		base64_md5: b64_md5,
		hex_hmac_md5: hex_hmac_md5,
		base64_hmac_md5: b64_hmac_md5
	};
});


/**
 *  基于第三方BASE64工具封装 
 *  
 *  样例：
 *  Snail.base64_encode('1234567890QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_+{}:"<>?') 
 *  	-> MTIzNDU2Nzg5MFFXRVJUWVVJT1BBU0RGR0hKS0xaWENWQk5NIUAjJCVeJiooKV8re306Ijw+Pw==
 *  
 *  Snail.base64_decode('MTIzNDU2Nzg5MFFXRVJUWVVJT1BBU0RGR0hKS0xaWENWQk5NIUAjJCVeJiooKV8re306Ijw+Pw==') 
 *  	-> 1234567890QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_+{}:"<>?
 */
Snail.extend(function(){
	
	var _BASE64_KEY_CHAR_="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";function encode(c){var a="";var k,h,f,j,g,e,d;var b=0;c=_utf8_encode(c);while(b<c.length){k=c.charCodeAt(b++);h=c.charCodeAt(b++);f=c.charCodeAt(b++);j=k>>2;g=((k&3)<<4)|(h>>4);e=((h&15)<<2)|(f>>6);d=f&63;if(isNaN(h)){e=d=64}else{if(isNaN(f)){d=64}}a=a+_BASE64_KEY_CHAR_.charAt(j)+_BASE64_KEY_CHAR_.charAt(g)+_BASE64_KEY_CHAR_.charAt(e)+_BASE64_KEY_CHAR_.charAt(d)}return a}function decode(c){var a="";var k,h,f;var j,g,e,d;var b=0;c=c.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(b<c.length){j=_BASE64_KEY_CHAR_.indexOf(c.charAt(b++));g=_BASE64_KEY_CHAR_.indexOf(c.charAt(b++));e=_BASE64_KEY_CHAR_.indexOf(c.charAt(b++));d=_BASE64_KEY_CHAR_.indexOf(c.charAt(b++));k=(j<<2)|(g>>4);h=((g&15)<<4)|(e>>2);f=((e&3)<<6)|d;a=a+String.fromCharCode(k);if(e!=64){a=a+String.fromCharCode(h)}if(d!=64){a=a+String.fromCharCode(f)}}a=_utf8_decode(a);return a}function _utf8_encode(a){a=a.replace(/\r\n/g,"\n");var b="";for(var e=0;e<a.length;e++){var d=a.charCodeAt(e);if(d<128){b+=String.fromCharCode(d)}else{if((d>127)&&(d<2048)){b+=String.fromCharCode((d>>6)|192);b+=String.fromCharCode((d&63)|128)}else{b+=String.fromCharCode((d>>12)|224);b+=String.fromCharCode(((d>>6)&63)|128);b+=String.fromCharCode((d&63)|128)}}}return b}function _utf8_decode(b){var a="";var d=0;var e=c1=c2=0;while(d<b.length){e=b.charCodeAt(d);if(e<128){a+=String.fromCharCode(e);d++}else{if((e>191)&&(e<224)){c2=b.charCodeAt(d+1);a+=String.fromCharCode(((e&31)<<6)|(c2&63));d+=2}else{c2=b.charCodeAt(d+1);c3=b.charCodeAt(d+2);a+=String.fromCharCode(((e&15)<<12)|((c2&63)<<6)|(c3&63));d+=3}}}return a};
	
	return {
		base64_encode: encode,
		base64_decode: decode
	};
});























/** 
 * GetDATA按钮
 * 
 * 创建人：Snail(snail_email@163.com)
 */

(function(scope, factory){
	
  var nameSpace = 'field_2021033118360000001';
  
  if(!window[nameSpace]){
	  
	  var Builder = factory();
	  
	  var plugin = window[nameSpace] = {
			  instance: {}
	  };
	  
	  plugin.init = function (options) {

		  var hasRender = (function(privateId){
			  
			  var els = document.querySelectorAll('#GET_DATA_' + privateId);
	    		
			  return (null != els && 0 < els.length);
		  })(options.privateId);
		  
		  if(!hasRender){ 
			  
		      plugin.instance[options.privateId] = new Builder(options);

			  console.log('[field_2021033118360000001 ' + options.privateId + '] Initialized .');
			  
		  }else{
			  
			  console.log('[field_2021033118360000001 ' + options.privateId + '] Repeated initialization !!!');
		  }
	  };
	  
	  plugin.isNotNull = function (obj) {
		  return true;
	  };
  }
})(this, function(){

	var temp_addNullOrActiveLineRecords = {};
	var temp_addNullOrActiveLineRecords_backfillData_index = {};
	var temp_addNullOrActiveLineRecords_backfillData = {};
	var temp_addNullOrActiveLineRecords_un_recordId = {};
	var temp_addNullOrActiveLineRecords_recordId = {};


	/**
	 *  默认值：/seeyon
	 */
	var appBasePath = (function(){
		
		var path = location.pathname;
		
		return path.substring(0, path.indexOf('/', 1));
	})();
	
	/**
	 * 获取TOKEN
	 */
	function getToken(){
		
		var token = null;
		
		if(window.cmp){	
			token = cmp.storage.get('CMP_V5_TOKEN', true);
		}
		
		if(!Snail.isBlank(token)){
			return token;
		}
		
		token = sessionStorage.getItem('CMP_V5_TOKEN');
		
		if(!Snail.isBlank(token)){
			return token;
		}
		
		return localStorage.getItem('CMP_V5_TOKEN');
	}
	
	/**
	 * 提交前缓存数据
	 */
	function preCommit(id, data, callback){
		
		Snail.http.post({
			url: (appBasePath + '/rest/snail/getdata/' + id + '/pre_commit'), 
			header:{'Content-Type': 'application/json', 'Accept': 'application/json', 'token': getToken()},
			data: {dataList: (Snail.isArray(data) ? data : [data])}, 
			oncomplete: function(responseText, status, xhr){

				console.log(responseText);
				
				callback && callback();
			}
		});
	}

	/**
	 * 生成模拟字段
	 */
	function generateSimulateFieldObject(tableName, field, formType, recordId){
		var obj = {
			attachmentInfo: undefined,
			attrs: {placeHolder: "", ctrlBorderStyle: "all", ctrlTitleStyle: "inline"},
			auth: "edit",
			clientId: "clientId1",
			ctrlBorderStyle: "all",
			ctrlTitleStyle: "inline",
			ctrlType: "suiText",
			customFieldInfo: null,
			digitNum: "0",
			display: "不在视图中的字段",
			enums: undefined,
			extra: {},
			fieldLength: 255,
			fieldType: "VARCHAR",
			formType: formType,
			formatType: "",
			hideCtrlBorder: true,
			id: field,
			inputType: "text",
			isAttachment: "0",
			isContorlChecked: "0",
			isCustomField: "0",
			isInCalculate: "0",
			isInCondition: undefined,
			isNotNull: "0",
			isSameValue: false,
			placeHolder: "",
			radioAlignType: undefined,
			relationData: {},
			relationInfo: [],
			showValue: "",
			showValue2: "",
			triggerData: {},
			type: "text",
			value: ""
		};
		
		if('formmain' == formType){
			
			obj['Xkey'] = (tableName + "__" + field);
			
		}else if('formson' == formType){
			
			// 样例：front_formson_1__records__0__lists__field0010__-1084740430627847537
			obj['Xkey'] = (tableName + "__records__0__lists__" + field + '__' + recordId);
			obj['recordId'] = recordId;
		}
		
		return obj;
	}

	/**
	 * 回填子表（当前行）
	 */
	function backfillSonSingleRecord(data, adaptation, privateId, recordId, contentDataId, tableName, app){
		  
		var config = data.config;
		var records = data.data;
		var mappings = config.mapping.data;
		
		var backfillData = {
				tableName: tableName,
				tableCategory: 'formson',
				updateData: {},
				updateRecordId: recordId
			};
		
		var key = null;
		var inKey = null;
		var value = null;
		var tableName = null;
		var editable = false;
		
		for(var i=0,len=mappings.length; i<len; i++){
			
			tableName = mappings[i].tableName;
			
			if(0 != tableName.indexOf('formson')){
				continue;
			}
			
			key = mappings[i].key;
			inKey = mappings[i].inKey;
			inSKey = inKey + '_showvalue';
			
			value = ((records && records[0] && null != records[0][inKey]) ? records[0][inKey] : '');
			showValue = ((records && records[0] && records[0][inSKey]) ? records[0][inSKey] : value);
			
			editabl = mappings[i].editable;
			
			backfillData.updateData[key] = {
				showValue: showValue,
				showValue2: showValue,
				value: value,
				valueId: value,
				auth: (editabl ? 'edit': 'browse')
			};
		}
		
		/** 
		 * 优化对不在视图中的字段进行赋值（注：在“保存待发”后再发起会造成数据丢失）
		 * 
		 * 变理
		 * @snail:2021-08-09 取消
		for(var frontTableName in windowFormData.formsons){
			
			if(tableName == windowFormData.formsons[frontTableName]['tableName']){
				
				for(var name in backfillData.updateData){
					
					var _records = windowFormData.formsons[frontTableName].records;
					
					for(var i=0,len=_records.length; i<len; i++){
						
						if(!_records[i]){
							continue;
						}
						
						var _recordId = _records[i].recordId;
						
						if(!_records[i].lists[name]){
							
							_records[i].lists[name] = generateSimulateFieldObject(frontTableName, name, 'formson', _recordId);
						}
					}
				}
			}
		}*/
		
		preCommit(contentDataId, backfillData, function(){
			
			adaptation.backfillFormControlData(backfillData, privateId);
			
		});
		
	}
	
	/**
	 * 回填子表
	 */
	function backfillSonRecord(data, adaptation, privateId, contentDataId, app){
		
		var config = data.config;
		var records = data.data;
		var mappings = config.mapping.data;
		

		var tableMappings = {};
		
		for(var i=0,len=mappings.length; i<len; i++){
			
			var tableName = mappings[i].tableName;
			
			if(0 == tableName.indexOf('formmain')){
				continue;
			}
			
			tableMappings[tableName] = tableMappings[tableName] || [];
			
			tableMappings[tableName].push(mappings[i]);
		}
		
		
		for(var tableName in tableMappings){

			var frontTableName = tableMappings[tableName][0].frontTableName;
			var formsonApp = (function(_root, _frontTableName){  // 查询子表
				
				function find(obj, level){
					
					if(0 >= level){
						return null;
					}
					
					if(obj.insertRow 
						&& obj.formsons && _frontTableName == obj.formsons.frontTableName){
						
						return obj;
					}
					
					if(!obj.$children){
						return null;
					}
					
					
					for(var i=0,len=obj.$children.length; i<len; i++){
						
						var cObj = obj.$children[i];
						
						cOjb = find(cObj, (level-1));
						
						if(null != cOjb){
							return cOjb;
						}
					}
					
					return null;
				}
				
				return find(_root, 20);
				
			})(app.el.__vue__.$root, frontTableName);
			
			if(!formsonApp){
				continue;
			}
			
			temp_addNullOrActiveLineRecords_backfillData_index[tableName] = 0;
			temp_addNullOrActiveLineRecords_backfillData[tableName] = [[]];
			temp_addNullOrActiveLineRecords_un_recordId[tableName] = [[]];
			temp_addNullOrActiveLineRecords_recordId[tableName] = {};
			
			var unPageSize = (function(_records){
				
				var size = 0;
				
				for(var j=0,jlen=_records.length; j<jlen; j++){
					
					_record = _records[j];
					
					if(!_record){
						continue;
					}
					
					size++;
					
					for(var name in _record.lists){
						
						if(!Snail.isBlank(_record.lists[name].value)){
							size--;
							break;
						}
					}
				}
				
				return size;
			})(formsonApp.formsons.records);
			
			var totalRowSize = formsonApp.pageData.total;
			var pageSize = formsonApp.pageData.pageSize;
			var rowIndex = (((totalRowSize>unPageSize) ? (totalRowSize-unPageSize) : totalRowSize) % pageSize);
			var pageIndex = 0;
			
			for(var i=0,len=records.length; i<len; i++){
				
				var _record = null;
				var _recordId = null;
				var _records = formsonApp.formsons.records;
				
				var _mappings = tableMappings[tableName];
				
				for(var j=0,jlen=_records.length; j<jlen; j++){
					
					_record = _records[j];
					
					if(!_record){
						continue;
					}
					
					if(temp_addNullOrActiveLineRecords_recordId[tableName][_record.recordId]){
						continue;
					}

					_recordId = _record.recordId;
					
					for(var name in _record.lists){
						
						if((_record.lists[name].type && 'linenumber' == _record.lists[name].type) || 'linenumber' == formsonApp.formsons.fieldInfo[name].inputType){
							continue;
						}
						
						var existName = false;
						
						for(var k=0,klen=_mappings.length; k<klen; k++){
							
							if(name == _mappings[k].key){
								existName = true;
								break;
							}
						}
						
						if(!existName){
							continue;
						}
						
						if(!Snail.isBlank(_record.lists[name].value)){
							_recordId = null;
							break;
						}
					}
					
					if(null != _recordId){
						break;
					}
				}
				
				if(null == _recordId){
					
					temp_addNullOrActiveLineRecords_un_recordId[tableName][pageIndex].push('');
					
				}else{

					temp_addNullOrActiveLineRecords_recordId[tableName][_recordId] = true;
				}
						
				var backfillData = {
						tableName: tableName,
						tableCategory: 'formson',
						updateData: {},
						updateRecordId: _recordId
					};
				
				var _key = null;
				var _inKey = null;
				var _value = null;
				var _editable = false;
				
				for(var j=0,jlen=_mappings.length; j<jlen; j++){
					
					_key = _mappings[j].key;
					_inKey = _mappings[j].inKey;
					_inSKey = _inKey + '_showvalue';
					
					_value = (null != records[i][_inKey] ? records[i][_inKey] : '');
					_showValue = (records[i][_inSKey] ? records[i][_inSKey] : _value);
					
					_editabl = _mappings[j].editable;
					
					backfillData.updateData[_key] = {
						showValue: _showValue,
						showValue2: _showValue,
						value: _value,
						valueId: _value,
						auth: (_editabl ? 'edit': 'browse')
					};
				}
				
				temp_addNullOrActiveLineRecords_backfillData[tableName][pageIndex].push(backfillData);
				
				rowIndex++
				
				if(rowIndex>=pageSize){
					
					temp_addNullOrActiveLineRecords_backfillData[tableName].push([]);
					temp_addNullOrActiveLineRecords_un_recordId[tableName].push([]);
					
					pageIndex++;
					
					rowIndex = 0;
				}
			}
			
			// 重写 addNullOrActiveLineRecords 方法
			if(null == temp_addNullOrActiveLineRecords[frontTableName]){
				
				temp_addNullOrActiveLineRecords[frontTableName] = formsonApp.addNullOrActiveLineRecords;
				
				formsonApp.addNullOrActiveLineRecords = function(obj){
					
					var currentTableName = obj.listTable.tableName;
					var currentIndex = temp_addNullOrActiveLineRecords_backfillData_index[currentTableName];
					
					if(null == currentIndex){
						
						alert('表单数据绑定异常，请重新绑定！！！');
						
						return;
					}
					
					var newObj = (function(_tableName, _cache_index){
						
						return {
							listTable: obj.listTable,
							data: obj.data,
							formsons: obj.formsons,
							message: obj.message,
							content: obj.content,
							active: true,
							ThirdAddArr: temp_addNullOrActiveLineRecords_un_recordId[_tableName][_cache_index],
							callback:function(result){
								
								var backfillDatas = temp_addNullOrActiveLineRecords_backfillData[_tableName][_cache_index];
								
								var i = 0;
								
								for(var j=0,jlen=backfillDatas.length; j<jlen; j++){
									
									if(null == backfillDatas[j].updateRecordId){
										
										backfillDatas[j].updateRecordId = result.tableData[_tableName].add[i].recordId;
										
										i++;
									}
								}

								obj.callback(result);
								
								/** 
								 * 优化对不在视图中的字段进行赋值（注：在“保存待发”后再发起会造成数据丢失）
								 * 
								 * 变更
								 * @snail:2021-08-09 取消
								for(var frontTableName in windowFormData.formsons){
									
									if(_tableName == windowFormData.formsons[frontTableName]['tableName']){
										
										for(var name in backfillDatas[0].updateData){
											
											var _records = windowFormData.formsons[frontTableName].records;
											
											for(var i=0,len=_records.length; i<len; i++){
												
												if(!_records[i]){
													continue;
												}
												
												var _recordId = _records[i].recordId;
												
												if(!_records[i].lists[name]){
													
													_records[i].lists[name] = generateSimulateFieldObject(frontTableName, name, 'formson', _recordId);
												}
											}
										}
									}
								} */

								preCommit(contentDataId, backfillDatas, function(){
									
									adaptation.backfillFormControlData(backfillDatas, privateId);
									
								});
							}
						};
					})(currentTableName, currentIndex);
					
					temp_addNullOrActiveLineRecords_backfillData_index[currentTableName]++;
					
					temp_addNullOrActiveLineRecords[frontTableName](newObj);
				}
			}

			
			for(var i=0,len=pageIndex+1; i<len; i++){
				formsonApp.insertRow();
			}
			
			// 还原
			formsonApp.addNullOrActiveLineRecords = temp_addNullOrActiveLineRecords[frontTableName];
			temp_addNullOrActiveLineRecords[frontTableName] = null;
		}
		
	}
	
	/**
	 * 回填主表
	 */
	function backfillMainRecord(data, adaptation, privateId, contentDataId, tableName, app){
		  
		var config = data.config;
		var records = data.data;
		var mappings = config.mapping.data;
		
		var backfillData = {
				tableName: tableName,
				tableCategory: 'formmain',
				updateData: {},
				updateRecordId: null
			};
		
		var key = null;
		var inKey = null;
		var value = null;
		var editabl = false;
		var tableName = null;
		
		for(var i=0,len=mappings.length; i<len; i++){
			
			tableName = mappings[i].tableName;
			
			if(0 != tableName.indexOf('formmain')){
				continue;
			}
			
			key = mappings[i].key;
			inKey = mappings[i].inKey;
			inSKey = inKey + '_showvalue';
			
			value = ((records && records[0] && null != records[0][inKey]) ? records[0][inKey] : '');
			showValue = ((records && records[0] && records[0][inSKey]) ? records[0][inSKey] : value);
			
			editabl = mappings[i].editable;
			
			backfillData.updateData[key] = {
				showValue: showValue,
				showValue2: showValue,
				value: value,
				valueId: value,
				auth: (editabl ? 'edit': 'browse')
			};
		}

		/** 
		 * 优化对不在视图中的字段进行赋值
		 * 
		 * 变更
		 * @snail:2021-08-09 取消
		if(windowFormData.formmains[tableName]){
			
			for(var name in backfillData.updateData){
				
				if(!windowFormData.formmains[tableName][name]){
					
					windowFormData.formmains[tableName][name] = generateSimulateFieldObject(tableName, name, 'formmain');
				}
			}
		}*/
		
		preCommit(contentDataId, backfillData, function(){
			
			adaptation.backfillFormControlData(backfillData, privateId);
			
		});
	}

	  
  /**
   * 构造函数
   * @param options
   * @constructor
   */
  function App(options) {
  
	  // 初始化参数
	  this.init(options);
	  
	  this.initCtrl();
  }
  
  App.prototype = {
		  
	init: function (options) {
		
		this.title = 'GetDATA';

		this.id = options.id;
		this.el = options.el;
		this.data = options.getData;
		this.field = options.field;
		this.formMessage = options.formMessage;
		this.adaptation = options.adaptation;
		this.privateId = options.privateId;
		this.preUrl = options.url_prefix;
		this.auth = options.getData.auth;
		this.hasEvent = true;

		
		this.customParam = this.data.customFieldInfo.customParam.snail_get_data;
		this.config = this.customParam ? this.customParam.config : null;
		this.mark = this.customParam ? this.customParam.mark : null;
		this.button = this.customParam ? this.customParam.button : {name: null, position: 0, type: 1};
		this.lock = ((this.config && this.config.other && this.config.other.formField) ? ('1' == this.config.other.formField.lock || 1 == this.config.other.formField.lock) : false);
		this.silent = ((this.config && this.config.other && this.config.other.formField) ? ('1' == this.config.other.formField.silent || 1 == this.config.other.formField.silent) : false);
		
		this.recordId = this.data.recordId;
		this.tableName = this.formMessage.tableName;
	},
	
    initCtrl: function () {

    	var _this = this;
    	var el = this.el;
    	
    	if('edit' != this.auth && 1 == this.button.position && 'formmain' == this.formMessage.tableCategory){
    		
    		var addBtnToToolbar = function(_el, privateId){
    			
    			_el = _el.parentNode;
    			
    			var id = _el.getAttribute('id');
    			
    			if(null != id && 0 == id.indexOf('tableName-front_formson_')){
    				
    				Snail.appendHtml('#' + id + '>div:first-child div.toolbarButton-box', '<div id="GET_DATA_' + privateId + '" class="formson-list__button cap-btn"></div>');
    				
    			}else if(id == 'mineFormPage'){
    				// 退出
    			}else{
    				
    				addBtnToToolbar(_el, privateId);
    			}
    		}
    		
    		addBtnToToolbar(el, this.privateId);
    		
    		var els = document.querySelectorAll('#GET_DATA_' + this.privateId);
    		
    		if(els[0]){
    			el = els[0];
    		}
    	}
    	
    	if(0 == this.button.type){
    		
    		this.hasEvent = false;
    		
    	}else if(2 == this.button.type){
    		
    		Snail.appendHtml(el, '<span style="height: 28px; line-height: 28px; display: inline-block;"><i class="CAP cap-icon-bianji" style="color: rgb(31, 133, 236); height: 28px; line-height: 28px;"></i></span><span style="height: 28px; line-height: 28px; display: inline-block;">' + (this.button.name || this.data.display) + '</span>');
        	
    		Snail.setCSS(el, {
        		'height': '28px', 
        		'line-height': '28px', 
        		'padding': '0px 15px',
        		'cursor': 'pointer',
        		'display': 'inline-block',
        		'width': 'auto'
        	});
        	
    	}else if(3 == this.button.type){
    		
    		Snail.appendHtml(el, '<span style="height: 28px; line-height: 28px; display: inline-block;"><i class="CAP cap-icon-bianji" style="color: rgb(31, 133, 236); height: 28px; line-height: 28px;"></i></span>');
        	
        	Snail.setCSS(el, {
        		'height': '30px', 
        		'line-height': '28px', 
        		'padding': '0px',
        		'cursor': 'pointer',
        		'display': 'inline-block',
        		'width': 'auto'
        	});
        
    	}else if(4 == this.button.type){ 
    		
    		this.hasEvent = false;
    		
    		Snail.appendHtml(el, '<span id="GET_DATA_DISPLAY_VALUE_' + this.privateId + '">' + this.data.showValue + '</span>');
    		
    	}else{
    		
    		Snail.appendHtml(el, '<span style="height: 28px; line-height: 28px; display: inline-block;"><i class="CAP cap-icon-bianji" style="color: rgb(31, 133, 236); height: 28px; line-height: 28px;"></i></span><span style="height: 28px; line-height: 28px; display: inline-block;">' + (this.button.name || this.data.display) + '</span>');
        	
    		Snail.setCSS(el, {
        		'width': 'auto',
        		'height': '30px', 
        		'line-height': '28px', 
        		'padding': '0px 15px',
        		'margin-right': '6px',
        		'border': '1px solid rgb(212, 212, 212)', 
        		'border-radius': '15px',
        		'background-color': '#ffffff',
        		'cursor': 'pointer',
        		'display': 'inline-block',
        		'white-space': 'nowrap',
        		'float': 'left'
        	});
    	}
    	
    	if('edit' != this.auth){ // 非编辑状态
		
			Snail.setCSS(el, { 'opacity': '0.6' });

    		return ;
    	}
    	
    	if(!window.csdk){
			console.warn('当前版本下无CSDK，因此GetDATA部分功能将失效，请谨慎应用！！！');
    	}
    	
    	/**
    	 *  控制字段是否可编辑 
    	 */ 
    	if(this.lock){
    		
    		if(this.customParam.config && this.customParam.config.mapping){
        		
        		var notEditable = Snail.get('__GET_DATA_SUBTABLE_NOT_EDITABLE_DATA__');
        		var notEditableKey = Snail.get('__GET_DATA_SUBTABLE_NOT_EDITABLE_KEY__');
        		
        		if(null == notEditable){
        			
        			Snail.put('__GET_DATA_SUBTABLE_NOT_EDITABLE_DATA__', notEditable = []);
        			Snail.put('__GET_DATA_SUBTABLE_NOT_EDITABLE_KEY__', notEditableKey = {});
        		}
        		
        		var mapping = this.customParam.config.mapping.data;
        		
        		for(var i=0,len=mapping.length; i<len; i++){
        			
        			if(false == mapping[i].editable){
        				
        				if(notEditableKey[mapping[i].key]){
        					continue;
        				}
        				
        				notEditable.push([
        					mapping[i].key,
    						mapping[i].frontTableName,
    						mapping[i].tableName,
    						this.field,
    						this.data,
    						this.lock
        				]);
        				
        				notEditableKey[mapping[i].key] = true;
        			}
        		}
        		
        		if(0 < notEditable.length){
        			
            		Snail.$on('__GET_DATA_SUBTABLE_NOT_EDITABLE__', function(){
            			
            			var notEditable = Snail.get('__GET_DATA_SUBTABLE_NOT_EDITABLE_DATA__');
            			
            			if(1 > notEditable.length){
            				return;
            			}
            			
            			for(var i=0,len=notEditable.length; i<len; i++){
            				
            				var frontTableName = notEditable[i][1];
    						
    						var getdataField = notEditable[i][3];
    						var getdataFieldName = getdataField.id;
    						var getdataTableName = getdataField.__tableName || (function(getdataField){
    							
    							if('formmain' == getdataField.formType){
    								
    								for(var tableName in windowFormData.formmains){
        								
        								if(windowFormData.formmains[tableName][getdataField.id]){
        									
        									return getdataField['__tableName'] = tableName;
        								}
        							}

    							}else{
    								
    								for(var tableName in windowFormData.formsons){
    									    								
        								if(windowFormData.formsons[tableName].records[0].lists[getdataField.id]){
        									
        									return getdataField['__tableName'] = tableName;
        								}
        							}
    							}
    							
    						})(getdataField);

            				
            				if('front_formmain' == frontTableName){
            					
            					var tableName = notEditable[i][2];
        						var formmainData = notEditable[i][4].formdata.formmains[tableName];   
        						
        						var isBrowse = false;

        						if(notEditable[i][5]){
        							
        							isBrowse = true;
        							
        						}else{
        							
        							if('formmain' == getdataField.formType){
        								
        								if(!Snail.isBlank(windowFormData.formmains[getdataTableName][getdataFieldName].value)){
        									
        									isBrowse = true;
        								}
            							
            						}else{
            							
            							var _records = windowFormData.formsons[getdataTableName].records;
            							
            							var hasValue = false;
            							
            							for(var j=0,jlen=_records.length; j<jlen; j++){
            								
            								if(_records[j] && _records[j].lists[getdataFieldName]){
            									
            									if(!Snail.isBlank(_records[j].lists[getdataFieldName].value)){
            										
            										hasValue = true;
            										break;
            									}
            								}
            							}
            							
            							if(hasValue){
            								isBrowse = true;
            							}
            						}
        						}
        						
        						if(isBrowse && formmainData[notEditable[i][0]]){
        							formmainData[notEditable[i][0]].auth = 'browse';
        						}
            					
            				}else{
            					
            					var formsonData = notEditable[i][4].formdata.formsons[frontTableName];
                				
                				if(formsonData){
                					
                					var records = formsonData.records;
                					
                					for(var j=0,jlen=records.length; j<jlen; j++){
                						
                						if(!records[j]){
                							
                							continue;
                						}

                						var isBrowse = false;
                						
                						if(notEditable[i][5]){
                							
                							isBrowse = true;
                							
                						}else{
                							
                							if('formmain' == getdataField.formType){
                    							
                								
                								if(!Snail.isBlank(windowFormData.formmains[getdataTableName][getdataFieldName].value)){
                									
                									isBrowse = true;
                    							}
                    							
                    						}else{
                    							
                    							var _records = windowFormData.formsons[getdataTableName].records;
                    							
                    							var hasValue = false;
                    							
                    							for(var k=0,klen=_records.length; k<klen; k++){
                    								
                    								if(_records[k] && _records[k].lists[getdataFieldName]){
                    									
                    									if(_records[k].recordId == records[j].recordId 
                    											&& !Snail.isBlank(_records[k].lists[getdataFieldName].value)){
                    										
                    										hasValue = true;
                    										break;
                    									}
                    								}
                    							}
                    							
                    							if(hasValue){
                    								isBrowse = true;
                    							}
                    						}
                						}
                						
                						if(isBrowse && records[j].lists[notEditable[i][0]]){
                							records[j].lists[notEditable[i][0]].auth = 'browse';
                						}
                					}
                				}
            				}
            			}
            		});
        		}
        	}
        	
    		window.csdk && csdk.event.on('recordAdded', function(){
        		Snail.$emit('__GET_DATA_SUBTABLE_NOT_EDITABLE__');
        	});
        	
    		window.csdk && csdk.event.on('recordCopied', function(){
        		Snail.$emit('__GET_DATA_SUBTABLE_NOT_EDITABLE__');
        	});
        	
    		window.csdk && csdk.event.on('recordDeleted', function(){
        		Snail.$emit('__GET_DATA_SUBTABLE_NOT_EDITABLE__');
        	});
        	
    		window.csdk && csdk.event.on('formUpdated', function(){
        		Snail.$emit('__GET_DATA_SUBTABLE_NOT_EDITABLE__');
        	});
        	
    		window.csdk && csdk.event.on('formRendered', function(){
        		Snail.$emit('__GET_DATA_SUBTABLE_NOT_EDITABLE__');
        	});
    	}
    	/* END */
 
    	
    	/**
    	 *  监听已绑定字段的参数变化(静默查询)
    	 */  
    	if(this.silent){
    		
    		var queryParams = Snail.get('__GET_DATA_SILENT_QUERY_DATA_' + this.privateId);
    		var queryConfig = Snail.get('__GET_DATA_SILENT_QUERY_CONIF_' + this.privateId);
    		
    		if(null == queryParams){
        		
    			queryParams = {};
    			queryConfig = {};
    			
    			var inConfig = this.config.dataset['in'];
    			
    			for(var i=0,len=inConfig.length; i<len; i++){
					
					queryParams[inConfig[i].key] = null;
					
    				if(!Snail.isBlank(inConfig[i].inKey)){
    					
    					queryConfig[inConfig[i].inKey] = inConfig[i];
    				}
    			}
    			
    			Snail.put(('__GET_DATA_SILENT_QUERY_DATA_' + this.privateId), queryParams);
    			Snail.put(('__GET_DATA_SILENT_QUERY_CONIF_' + this.privateId), queryConfig);
    		}
    		
    		Snail.$on(('__GET_DATA_SILENT_QUERY_' + this.privateId), function(params){
    			        		
    			_this.silentQuery(params);
    			
    			Snail.put('__GET_DATA_SILENT_QUERY_PARAMS_' + _this.privateId, Snail.hex_md5(Snail.toJSONString(params)));
    			
    			console.log('[GetDATA] 记录查询标记', Snail.hex_md5(Snail.toJSONString(queryParams)));
    		});
    		
    		window.csdk && csdk.event.on('fieldChanged', function(ev){

        		var hasChanged = true;
        		var queryParams = Snail.get('__GET_DATA_SILENT_QUERY_DATA_' + _this.privateId);
        		var queryConfig = Snail.get('__GET_DATA_SILENT_QUERY_CONIF_' + _this.privateId);
        		
        		for(var n in queryConfig){
        			
        			var tableName = n.substring(0, n.indexOf('.'));
        			var fieldId = n.substring(n.indexOf('.') + 1);
        			
        			var queryConfigItem = queryConfig[n];
        			
        			if(!queryConfigItem){
        				continue;
        			}
        			
        			queryParams[queryConfigItem.key] = (function(_fieldId, _tableName, _formdata, _recordId){
    					
        				if(_formdata.formmains && _formdata.formmains[_tableName]){
    						
    						var formmain = _formdata.formmains[_tableName];
    						
    						return (formmain[_fieldId] ? formmain[_fieldId].value : null);
    					}
    					
    					if(_recordId && _formdata.formsons){
    						
    						for(var n in _formdata.formsons){
    							
    							if(_formdata.formsons[n] && _tableName == _formdata.formsons[n].tableName){
    								
    								var records = _formdata.formsons[n].records;
    	    						
    	    						for(var i=0,len=records.length; i<len; i++){
    	    							
    	    							if(!records[i]){
    										continue;
    									}
    	    							
    	    							if(_recordId == records[i].recordId){
    										
    	    								return ((records[i].lists && records[i].lists[_fieldId]) ? records[i].lists[_fieldId].value : null);
    									}
    	    						}
    							}
    						}
    					}
    					
    				})(fieldId, tableName, _this.data.formdata, _this.recordId);
        			
        			if(Snail.isBlank(queryParams[queryConfigItem.key])){
        				hasChanged = false;
        			}
        		}
        		
        		if(!hasChanged && ev){
        			
        			if(Snail.isObject(ev) && ev.tableName && ev.tableName && ev.value){
	        			
	        			ev = [ev];
	        		}
        			
        			for(var i=0,len=ev.length; i<len; i++){
	        			
	        			if(queryConfig[ev[i].tableName + '.' + ev[i].id]){
	        				
	        				hasChanged = true;
	        				
	        				break;
	        			}
        			}
        		}
        		
        		if(Snail.hex_md5(Snail.toJSONString(queryParams)) == Snail.get('__GET_DATA_SILENT_QUERY_PARAMS_' + _this.privateId)){
        			
        			console.log('[GetDATA] 阻止重复查询！', Snail.hex_md5(Snail.toJSONString(queryParams)), Snail.toJSONString(queryParams));
        			
        			return ;
        		}
        		
        		hasChanged && Snail.$emit(('__GET_DATA_SILENT_QUERY_' + _this.privateId), queryParams);
        	});
        
    	}
    	/* END */
    	
    	this.adaptation.ObserverEvent.listen('Event' + this.privateId, function(data) {
    		
    		Snail.setEleValue(('#GET_DATA_DISPLAY_VALUE_' + _this.privateId), data.showValue);
    	});
    	
    	
    	if(this.customParam.config && this.customParam.config.auth && ('1' != this.customParam.config.auth[1])){
    		this.title += '　[\u8bd5\u7528]';
    	}
    	
    	this.hasEvent && Snail.bindEvent(el, 'click', function(event){ 
    		_this.openDialog(_this.title, _this.data, _this.mark, _this.adaptation, _this.recordId, _this.privateId, _this.tableName); 
    	});
    },
    
    openDialog: function(title, data, mark, adaptation, recordId, privateId, tableName) {
    	
		var _this = this;
    	var contentDataId = data.formdata.content.contentDataId;
    	
		// 回填数据
    	var fnBackfillForm = function(data, recordId){
    		
			if(Snail.isBlank(recordId)){
				
				backfillMainRecord(data, adaptation, privateId, contentDataId, tableName, _this);
				
				if(window.csdk){
					
					backfillSonRecord(data, adaptation, privateId, contentDataId, _this);
				}
				
			}else{
				
				backfillSonSingleRecord(data, adaptation, privateId, recordId, contentDataId, tableName, _this);
			}
    	}
    	
    	window.getdataDialog = getCtpTop().$.dialog({
	        id: ('GetDATAView_' + privateId),
	        url: (appBasePath + '/plugin/formext/getdata/index.html?tt=' + Date.now()),
	        width: (top.document.body.clientWidth - 100),
	        height: (top.document.body.clientHeight - 180),
	        title: title,
	        targetWindow:getCtpTop(),
	        transParams: {
	        	dialog: { 
	        		close: function(){
	        			getdataDialog.close();
	        		},
	        		backfillForm: function(data){
	        			
	        			fnBackfillForm(data, recordId);
	        			
	        			getdataDialog.close();
	        		}
	        	},
	        	data: data,
	        	recordId: recordId,
	        	mark: mark,
	        	selection: (recordId == null ? true : false)
	        },
	        buttons: [{
				text: '确认',
				id: "sure",
				isEmphasize: true,
				handler: function() {
					
					var result = getdataDialog.getReturnValue();
					
					if (200 != result.code) {
						return (result.message ? alert(result.message) : null);
					}
					
					// 回填数据
					fnBackfillForm(result.data, recordId);
					
					getdataDialog.close();
				}
			},{
				text: '取消',
				id: "exit",
				handler: function() {
					
					getdataDialog.close();
				}
			}]
	      });
    },
    silentQuery: function(params){
    	
    	var _this = this;
		
		Snail.http.post({
			url: (appBasePath + '/snail/formext/getdata.do?method=getData&mark=' + this.mark),
			header: {
				'Content-Type': 'application/json', 'Accept': 'application/json',
				'pagination.page': 1, 
				'pagination.per_page_size': 20
			},
			data: (function(_params){
				
				var param = {};
				
				if('groovy' == _this.config.dataset.script.type 
						|| 'http' == _this.config.dataset.script.type){
					
					param['pagination'] = { page: 1, per_page_size: 20 };
				}
				
				if(Snail.isObject(_params)){
					
					for(var n in _params){
						
						param[n] = _params[n];
					}
				}
				
				return param;
			})(params),
			onsuccess: function(result, status, xhr){
				
				if(200 == result.code){
										
					var data = {
						data: result.data,
						config: _this.config
					};
					
					// 回填数据
					if(Snail.isBlank(_this.recordId)){
						
						backfillMainRecord(data, _this.adaptation, _this.privateId, _this.data.formdata.content.contentDataId, _this.tableName, _this);
						
					}else{
						
						backfillSonSingleRecord(data, _this.adaptation, _this.privateId, _this.recordId, _this.data.formdata.content.contentDataId, _this.tableName, _this);
					}

				} else {
					alert(result.message);
				}
				
			},
			onerror: function(responseText, status, xhr){
				
				console.log(responseText);
				
				alert(responseText);
			}
		});
    },
    destroy: function () {
      ;
    }
  };

  return App;
});
